Errores de Google Distributed Cloud con air gap

En este capítulo se ofrece una descripción general del modelo de errores de las APIs de Google Distributed Cloud aislado (GDC). También ofrece directrices generales a los desarrolladores sobre cómo generar y gestionar errores correctamente.

Las APIs de GDC usan un modelo de errores sencillo e independiente del protocolo, lo que nos permite ofrecer una experiencia coherente en diferentes APIs, protocolos de APIs (como gRPC o HTTP) y contextos de errores (como errores asíncronos, por lotes o de flujo de trabajo).

Modelo de error

El modelo de errores de las APIs de GDC se define lógicamente mediante google.rpc.Status, de la que se devuelve una instancia al cliente cuando se produce un error en la API. El siguiente fragmento de código muestra el diseño general del modelo de error:

package google.rpc;

// The `Status` type defines a logical error model that is suitable for
// different programming environments, including REST APIs and RPC APIs.
message Status {
  // A simple error code that can be easily handled by the client. The
  // actual error code is defined by `google.rpc.Code`.
  int32 code = 1;

  // A developer-facing human-readable error message in English. It should
  // both explain the error and offer an actionable resolution to it.
  string message = 2;

  // Additional error information that the client code can use to handle
  // the error, such as retry info or a help link.
  repeated google.protobuf.Any details = 3;
}

Como la mayoría de las APIs de Google usan un diseño de API orientado a recursos, la gestión de errores sigue el mismo principio de diseño y utiliza un pequeño conjunto de errores estándar con un gran número de recursos. Por ejemplo, en lugar de definir diferentes tipos de errores "no encontrado", el servidor usa un código de error google.rpc.Code.NOT_FOUND estándar e indica al cliente qué recurso específico no se ha encontrado. El espacio de error más pequeño reduce la complejidad de la documentación, ofrece mejores asignaciones idiomáticas en las bibliotecas de cliente y reduce la complejidad de la lógica del cliente sin restringir la inclusión de información útil.

Códigos de error

Las APIs de GDC deben usar los códigos de error canónicos definidos por google.rpc.Code. Las APIs individuales deben evitar definir códigos de error adicionales, ya que es muy poco probable que los desarrolladores escriban lógica para gestionar un gran número de códigos de error. Por ejemplo, si se gestionaran una media de tres códigos de error por llamada a la API, la mayor parte de la lógica de la aplicación se dedicaría a la gestión de errores, lo que no sería una buena experiencia para los desarrolladores.

Mensajes de error

El mensaje de error debería ayudar a los usuarios a entender y resolver el error de la API de forma fácil y rápida. En general, ten en cuenta las siguientes directrices al escribir mensajes de error:

  • No supongas que el usuario es un experto en tu API. Los usuarios pueden ser desarrolladores de clientes, personal de operaciones, personal de TI o usuarios finales de aplicaciones.
  • No supongas que el usuario sabe nada sobre la implementación de tu servicio ni que está familiarizado con el contexto de los errores (como el análisis de registros).
  • Cuando sea posible, los mensajes de error deben redactarse de forma que un usuario técnico (pero no necesariamente un desarrollador de tu API) pueda responder al error y corregirlo.
  • El mensaje de error debe ser breve. Si es necesario, proporciona un enlace donde un lector confundido pueda hacer preguntas, enviar comentarios u obtener más información que no encaje bien en un mensaje de error. De lo contrario, usa el campo de detalles para ampliar la información.

Detalles de los errores

Las APIs de GDC definen un conjunto de cargas útiles de error estándar para los detalles de los errores, que puedes encontrar en google/rpc/error_details.proto. Cubren las necesidades más habituales en cuanto a errores de API, como fallos de cuota y parámetros no válidos. Al igual que los códigos de error, los desarrolladores deben usar estas cargas útiles estándar siempre que sea posible.

Solo se deben introducir tipos de detalles de error adicionales si pueden ayudar al código de la aplicación a gestionar los errores. Si la información de error solo puede gestionarla un humano, utiliza el contenido del mensaje de error y deja que los desarrolladores lo gestionen manualmente en lugar de introducir tipos de detalles de error adicionales.

Aquí tienes algunos ejemplos de cargas útiles de error_details:

  • ErrorInfo: proporciona información de error estructurada que es estable y extensible.
  • RetryInfo: describe cuándo pueden volver a intentar los clientes una solicitud fallida. Puede devolverse en Code.UNAVAILABLE o Code.ABORTED.
  • QuotaFailure: describe por qué ha fallado una comprobación de cuota. Se puede devolver en Code.RESOURCE_EXHAUSTED
  • BadRequest: Describe las infracciones de una solicitud de un cliente. Se puede devolver en Code.INVALID_ARGUMENT

Información del error

ErrorInfo es un tipo especial de carga útil de error. Proporciona información de errores estable y extensible en la que pueden confiar tanto los humanos como las aplicaciones. Cada ErrorInfo tiene tres elementos de información: un dominio de error, un motivo de error y un conjunto de metadatos de error. Para obtener más información, consulta la definición de ErrorInfo.

En el caso de las APIs de GDC, el dominio de error principal es googleapis.com y los motivos de error correspondientes se definen mediante la enumeración google.api.ErrorReason. Para obtener más información, consulta la definición de google.api.ErrorReason.

Localización de errores

El campo message de google.rpc.Status está orientado a los desarrolladores y debe estar en inglés.

Si necesitas mostrar un mensaje de error a los usuarios, usa google.rpc.LocalizedMessage en el campo de detalles. Aunque el campo de mensaje de google.rpc.LocalizedMessage se puede localizar, asegúrate de que el campo de mensaje de google.rpc.Status esté en inglés.

De forma predeterminada, el servicio de la API debe usar la configuración regional del usuario autenticado, el encabezado HTTP Accept-Language o el parámetro language_code de la solicitud para determinar el idioma de la localización.

Error de asignación

Se puede acceder a las APIs de GDC en diferentes entornos de programación. Cada entorno suele tener su propia forma de gestionar los errores. En las secciones siguientes se explica cómo se asigna el modelo de errores en los entornos de uso habitual.

Asignación HTTP

Aunque los mensajes de proto3 tienen una codificación JSON nativa, la plataforma de APIs de GDC usa un esquema de errores diferente para las APIs HTTP JSON de GDC por motivos de compatibilidad con versiones anteriores.

Esquema:

// This message defines the error schema for GDC JSON HTTP APIs.
message Error {
  // Deprecated. This message is only used by error format v1.
  message ErrorProto {}
  // This message has the same semantics as `google.rpc.Status`. It uses HTTP
  // status code instead of gRPC status code. It has extra fields `status` and
  // `errors` for backward compatibility with [GDC API Client
  // Libraries](https://developers.google.com/api-client-library).
  message Status {
    // The HTTP status code that corresponds to `google.rpc.Status.code`.
    int32 code = 1;
    // This corresponds to `google.rpc.Status.message`.
    string message = 2;
    // Deprecated. This field is only used by error format v1.
    repeated ErrorProto errors = 3;
    // This is the enum version for `google.rpc.Status.code`.
    google.rpc.Code status = 4;
    // This corresponds to `google.rpc.Status.details`.
    repeated google.protobuf.Any details = 5;
  }
  // The actual error payload. The nested message structure is for backward
  // compatibility with [GDC API Client
  // Libraries](https://developers.google.com/api-client-library). It also
  // makes the error more readable to developers.
  Status error = 1;
}

Ejemplo:

{
  "error": {
    "code": 400,
    "message": "API key not valid. Please pass a valid API key.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "API_KEY_INVALID",
        "domain": "googleapis.com",
        "metadata": {
          "service": "translate.googleapis.com"
        }
      }
    ]
  }
}

Asignación de gRPC

Los distintos protocolos RPC asignan el modelo de error de forma diferente. En el caso de gRPC, el modelo de error se admite de forma nativa en el código generado y en la biblioteca de tiempo de ejecución de cada lenguaje admitido. Puedes obtener más información en la documentación de la API de gRPC. Por ejemplo, consulta io.grpc.Status de gRPC Java.

Asignación de bibliotecas de cliente

Las bibliotecas de cliente de GDC pueden mostrar los errores de forma diferente en cada lenguaje para ser coherentes con las expresiones establecidas. Por ejemplo, la biblioteca google-cloud-go devolverá un error que implementa la misma interfaz que google.rpc.Status, mientras que google-cloud-java generará una excepción.

Gestionar errores

En la siguiente tabla se incluyen todos los códigos de error de gRPC definidos en google.rpc.Code y una breve descripción de su causa. Para gestionar un error, puedes consultar la descripción del código de estado devuelto y modificar la llamada en consecuencia.

HTTP gRPC Descripción
200 OK No hay errores.
400 INVALID_ARGUMENT El cliente especificó un argumento que no es válido. Consulta el mensaje y los detalles del error para obtener más información.
400 FAILED_PRECONDITION No se puede realizar la solicitud debido al estado actual del sistema, como eliminar un directorio que no está vacío.
400 OUT_OF_RANGE El cliente especificó un intervalo que no es válido.
401 UNAUTHENTICATED La solicitud no se ha autenticado porque el token de OAuth ha caducado, no es válido o no se ha encontrado.
403 PERMISSION_DENIED El cliente no tiene suficientes permisos. Esto puede ocurrir porque el token de OAuth no tiene los permisos adecuados, el cliente no tiene permiso o la API no se ha habilitado.
404 NOT_FOUND No se ha encontrado un recurso especificado.
409 ABORTED Se ha producido un conflicto de simultaneidad (por ejemplo, relacionado con acciones de lectura, modificación y escritura).
409 ALREADY_EXISTS El cliente ha intentado crear un recurso que ya existe.
429 RESOURCE_EXHAUSTED Se ha agotado la cuota del recurso o se ha alcanzado el límite de frecuencia. El cliente debe buscar el detalle del error google.rpc.QuotaFailure para obtener más información.
499 CANCELLED El cliente ha cancelado la solicitud.
500 DATA_LOSS Se han perdido o dañado los datos de forma irrecuperable. El cliente debe informar del error al usuario.
500 UNKNOWN Se ha producido un error de servidor desconocido. Normalmente, se trata de un error del servidor.
500 INTERNAL Error de servidor interno. Normalmente, se trata de un error del servidor.
501 NOT_IMPLEMENTED El servidor no ha implementado el método de API.
502 N/A Se ha producido un error de red antes de llegar al servidor. Normalmente, se trata de una interrupción de la red o de una configuración incorrecta.
503 UNAVAILABLE Servicio no disponible. Normalmente, el servidor no está operativo.
504 DEADLINE_EXCEEDED Se ha superado el plazo límite de la solicitud. Esto solo ocurrirá si el llamante establece un plazo que sea inferior al plazo predeterminado del método (es decir, el plazo solicitado no es suficiente para que el servidor procese la solicitud) y la solicitud no se ha completado en ese plazo.

Reintentar errores

Los clientes pueden reintentar las solicitudes con errores 503 UNAVAILABLE con un tiempo de espera exponencial. El retraso mínimo debe ser de 1 segundo, a menos que se indique lo contrario. La repetición predeterminada de los reintentos debe ser una vez, a menos que se indique lo contrario.

En el caso de los errores 429 RESOURCE_EXHAUSTED, el cliente puede volver a intentarlo en el nivel superior con un retraso mínimo de 30 segundos. Estos reintentos solo son útiles para tareas en segundo plano de larga duración.

En el resto de los casos, puede que no sea posible volver a intentarlo. Primero, asegúrate de que tu solicitud sea idempotente y consulta google.rpc.RetryInfo para obtener más información.

Propagar errores

Si tu servicio de API depende de otros servicios, no debes propagar ciegamente los errores de esos servicios a tus clientes. Cuando traduzcas errores, te recomendamos lo siguiente:

  • Oculta los detalles de implementación y la información confidencial.
  • Ajusta la parte responsable del error. Por ejemplo, un servidor que recibe un error INVALID_ARGUMENT de otro servicio debe propagar un error INTERNAL a su propio llamador.

Reproducir errores

Si no puedes resolver los errores analizando los registros y la monitorización, debes intentar reproducirlos con una prueba sencilla y repetible. Puedes usar la prueba para recoger más información para solucionar problemas, que puedes proporcionar al ponerte en contacto con el equipo de Asistencia técnica.

Te recomendamos que uses oauth2l, curl -v y Parámetros del sistema para reproducir errores con las APIs de GDC. Juntas, pueden reproducir casi todas las solicitudes de la API de GDC y proporcionarte información de depuración detallada. Para obtener más información, consulta las páginas de documentación correspondientes a la API que estés llamando.

Generar errores

Si eres desarrollador de servidores, debes generar errores con suficiente información para ayudar a los desarrolladores de clientes a comprender y resolver el problema. Al mismo tiempo, debes tener en cuenta la seguridad y la privacidad de los datos de los usuarios, y evitar revelar información sensible en el mensaje y los detalles de error, ya que los errores suelen registrarse y otras personas pueden acceder a ellos. Por ejemplo, un mensaje de error como "La dirección IP del cliente no está en la lista de permitidas 128.0.0.0/8" expone información sobre la política del lado del servidor, a la que puede que no tenga acceso el usuario que tiene acceso a los registros.

Para generar errores adecuados, primero debe familiarizarse con google.rpc.Code para elegir el código de error más adecuado para cada condición de error. Una aplicación de servidor puede comprobar varias condiciones de error en paralelo y devolver la primera.

En la siguiente tabla se muestra cada código de error y un ejemplo de un buen mensaje de error.

HTTP gRPC Ejemplo de mensaje de error
400 INVALID_ARGUMENT El campo x.y.z de la solicitud es xxx, pero se esperaba uno de los siguientes: [yyy, zzz].
400 FAILED_PRECONDITION El recurso xxx es un directorio que no está vacío, por lo que no se puede eliminar.
400 OUT_OF_RANGE El parámetro "age" está fuera del intervalo [0, 125].
401 UNAUTHENTICATED Las credenciales de autenticación no son válidas.
403 PERMISSION_DENIED Permiso "xxx" denegado en el recurso "yyy".
404 NOT_FOUND No se ha encontrado el recurso "xxx".
409 ABORTED No se ha podido obtener el bloqueo del recurso "xxx".
409 ALREADY_EXISTS El recurso "xxx" ya existe.
429 RESOURCE_EXHAUSTED Se ha superado el límite de cuota "xxx".
499 CANCELLED El cliente ha cancelado la solicitud.
500 DATA_LOSS Consulta la nota.
500 UNKNOWN Consulta la nota.
500 INTERNAL Consulta la nota.
501 NOT_IMPLEMENTED El método "xxx" no se ha implementado.
503 UNAVAILABLE Consulta la nota.
504 DEADLINE_EXCEEDED Consulta la nota.

Cargas útiles de error

El paquete google.rpc define un conjunto de cargas útiles de error estándar, que son preferibles a las cargas útiles de error personalizadas. En la siguiente tabla se indica cada código de error y su carga útil de error estándar correspondiente, si procede. Recomendamos que las aplicaciones avanzadas busquen estas cargas útiles de error en google.rpc.Status cuando gestionen errores.

HTTP gRPC Detalles de error recomendados
400 INVALID_ARGUMENT google.rpc.BadRequest
400 FAILED_PRECONDITION google.rpc.PreconditionFailure
400 OUT_OF_RANGE google.rpc.BadRequest
401 UNAUTHENTICATED google.rpc.ErrorInfo
403 PERMISSION_DENIED google.rpc.ErrorInfo
404 NOT_FOUND google.rpc.ResourceInfo
409 ABORTED google.rpc.ErrorInfo
409 ALREADY_EXISTS google.rpc.ResourceInfo
429 RESOURCE_EXHAUSTED google.rpc.QuotaFailure
499 CANCELLED
500 DATA_LOSS google.rpc.DebugInfo
500 UNKNOWN google.rpc.DebugInfo
500 INTERNAL google.rpc.DebugInfo
501 NOT_IMPLEMENTED
503 UNAVAILABLE google.rpc.DebugInfo
504 DEADLINE_EXCEEDED google.rpc.DebugInfo