Respuestas de error

Respuestas de error estándar

Si una solicitud a la API de Reporting se realiza correctamente, la API muestra un 200. Si se produce un error con una solicitud, la API muestra un código de estado HTTP, un estado y un motivo en la respuesta según el tipo de error. Además, el cuerpo de la respuesta contiene una descripción detallada de lo que causó el error. Este es un ejemplo de una respuesta de error:

{
 "error": {
  "code": 403,
  "message": "User does not have sufficient permissions for this profile.",
  "status": "PERMISSION_DENIED"
 }
}

Tabla de error

Código Estado Descripción Acción recomendada
400 INVALID_ARGUMENT La solicitud no es válida. Es posible que falte un argumento obligatorio, que exceda los límites o que tenga un valor no válido. Revisa el mensaje de error para obtener más detalles. Este error volverá a fallar si el cliente vuelve a intentarlo.
401 UNAUTHENTICATED El cliente no se autenticó correctamente. No vuelvas a intentar la operación sin solucionar el problema. Debes obtener un token de autenticación nuevo.
403 PERMISSION_DENIED Indica la solicitud de datos a los que el usuario no tiene acceso. No vuelvas a intentar la operación sin solucionar el problema. Debes obtener permisos suficientes para realizar la operación en la entidad especificada.
429 RESOURCE_EXHAUSTED AnalyticsDefaultGroupCLIENT_PROJECT-1d Indica que se agotó la cuota de solicitudes por día por proyecto. No vuelvas a intentar la operación sin solucionar el problema. Has agotado tu cuota diaria.
429 RESOURCE_EXHAUSTED AnalyticsDefaultGroupCLIENT_PROJECT-100s Indica que se agotó la cuota de solicitudes cada 100 segundos por proyecto. Vuelve a intentarlo con la retirada exponencial. Debes disminuir la velocidad a la que envías las solicitudes.
429 RESOURCE_EXHAUSTEDGrupodeValoresPredeterminadodeUSER-100 s Indica que se agotó la cuota de solicitudes cada 100 segundos por usuario, por proyecto. Vuelve a intentarlo con la retirada exponencial. Debes disminuir la velocidad a la que envías las solicitudes.
429 RESOURCE_EXHAUSTED DiscoveryGroupCLIENT_PROJECT-100s Indica que se agotó la cuota de solicitudes por 100 segundos de descubrimiento. La respuesta de descubrimiento no cambia con frecuencia. Almacena la respuesta en caché de forma local o vuelve a intentarlo con la retirada exponencial. Debes disminuir la velocidad a la que envías las solicitudes.
500 INTERNAL Se produjo un error interno inesperado del servidor. No vuelvas a intentar esta consulta más de una vez.
503 BACKEND_ERROR El servidor mostró un error. No vuelvas a intentar esta consulta más de una vez.
503 UNAVAILABLE El servicio no pudo procesar la solicitud. Lo más probable es que esta sea una condición transitoria y que se corrija si vuelves a intentar con la retirada exponencial.

Implementar retirada exponencial

La retirada exponencial es el proceso en el que un cliente vuelve a intentar de forma periódica una solicitud con errores durante un período creciente. Es una estrategia estándar de manejo de errores para aplicaciones de red. La API de Reporting se diseñó con la expectativa de que los clientes que reintenten las solicitudes fallidas lo hagan mediante la retirada exponencial. Además de ser “obligatorio”, la retirada exponencial aumenta la eficiencia del uso del ancho de banda, reduce la cantidad de solicitudes necesarias para obtener una respuesta correcta y maximiza la capacidad de procesamiento de solicitudes en entornos simultáneos.

El flujo para implementar una retirada exponencial simple es el siguiente.

  1. Cómo realizar una solicitud a la API
  2. Recibir una respuesta de error que tiene un código de error que se puede reintentar
  3. Espera 1 s + random_number_milliseconds segundos
  4. Reintentar solicitud
  5. Recibir una respuesta de error que tiene un código de error que se puede reintentar
  6. Espera 2 s + random_number_milliseconds segundos
  7. Reintentar solicitud
  8. Recibir una respuesta de error que tiene un código de error que se puede reintentar
  9. Espera 4 s + random_number_milliseconds segundos
  10. Reintentar solicitud
  11. Recibir una respuesta de error que tiene un código de error que se puede reintentar
  12. Espera 8 s + random_number_milliseconds segundos
  13. Reintentar solicitud
  14. Recibir una respuesta de error que tiene un código de error que se puede reintentar
  15. Espera 16 s + random_number_milliseconds segundos
  16. Reintentar solicitud
  17. Si aún recibes un error, detente y regístralo.

En el flujo anterior, random_number_milliseconds es un número aleatorio de milisegundos menor o igual que 1,000. Esto es necesario para evitar ciertos errores de bloqueo en algunas implementaciones simultáneas. random_number_milliseconds debe volver a definirse después de cada espera.

Nota: La espera siempre es (2 ^ n) + random_number_milliseconds, donde n es un número entero que aumenta de forma monótona definido inicialmente como 0. n se incrementa en 1 por cada iteración (cada solicitud).

El algoritmo está configurado para terminar cuando n sea 5. Este límite solo se aplica para evitar que los clientes vuelvan a intentarlo de forma infinita y genera un retraso total de alrededor de 32 segundos antes de que una solicitud se considere "un error irrecuperable".

El siguiente código de Python es una implementación del flujo anterior para recuperarse de errores que ocurren en un método llamado makeRequest.

import random
import time
from apiclient.errors import HttpError

def makeRequestWithExponentialBackoff(analytics):
  """Wrapper to request Google Analytics data with exponential backoff.

  The makeRequest method accepts the analytics service object, makes API
  requests and returns the response. If any error occurs, the makeRequest
  method is retried using exponential backoff.

  Args:
    analytics: The analytics service object

  Returns:
    The API response from the makeRequest method.
  """
  for n in range(0, 5):
    try:
      return makeRequest(analytics)

    except HttpError, error:
      if error.resp.reason in ['userRateLimitExceeded', 'quotaExceeded',
                               'internalServerError', 'backendError']:
        time.sleep((2 ** n) + random.random())
      else:
        break

  print "There has been an error, the request never succeeded."