Prueba cómo controla tu aplicación los límites de tasa de la API de GitHub

Tip

¿No conoce la limitación de velocidad? Aprenda qué es la limitación de velocidad y cómo gestionarla.

De un vistazo
Objetivo: Prueba cómo tu aplicación gestiona los límites de tasa de la API REST de GitHub
Tiempo: 15 minutos
Plugins:RateLimitingPlugin, GenericRandomErrorPlugin, RetryAfterPlugin
Requisitos previos:Configuración del proxy de desarrollo

La aplicación llama a la API de GitHub. Funciona en tu máquina, pero luego un trabajo de CI, una organización grande o un día de mucho tráfico hace que supere el límite de solicitudes y comienza a generar errores. Para probarlo con la API real, tendrías que agotar tu límite de solicitudes y, a continuación, esperar hasta una hora antes de poder volver a intentarlo. Dev Proxy simula localmente los límites de tasa de GitHub, con un límite y una ventana de tiempo que elijas.

Saber qué devuelve GitHub

GitHub tiene dos tipos de límites de tasa para la API REST.

Los límites de tasa principales limitan el número de solicitudes que se realizan por hora. Por ejemplo, 60 para solicitudes no autenticadas y 5000 para solicitudes con un token de acceso personal. Cada respuesta incluye encabezados que muestran dónde te encuentras:

Header Meaning
x-ratelimit-limit El número máximo de solicitudes por hora
x-ratelimit-remaining Número de solicitudes que quedan en la ventana actual
x-ratelimit-reset Hora a la que se restablece la ventana, en segundos de época UTC.

Cuando se supera el límite principal, GitHub devuelve 403 o x-ratelimit-remaining con 0 establecido en 429. No vuelva a intentarlo hasta la hora indicada en x-ratelimit-reset.

Los límites de tasa secundarios protegen a GitHub de picos, como demasiadas solicitudes simultáneas o crear demasiado contenido demasiado rápido. Cuando superas uno, GitHub devuelve 403 o 429 con un mensaje sobre un límite de tasa secundario. Si la respuesta tiene un encabezado retry-after, espere ese número de segundos. De lo contrario, espere al menos un minuto y aumente el tiempo de espera si la solicitud sigue fallando.

GitHub puede prohibir las integraciones que siguen enviando solicitudes mientras están sujetas a limitación de tasa. Para obtener más información, consulte Límites de tasa para la API REST en la documentación de GitHub.

Simular el límite de tasa principal

Usa RateLimitingPlugin para contar las solicitudes y devolver los encabezados de límite de velocidad de GitHub. Para probar sin esperar una hora, use un límite pequeño y una ventana corta.

Archivo: devproxyrc.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/rc.schema.json",
  "plugins": [
    {
      "name": "RetryAfterPlugin",
      "enabled": true,
      "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
    },
    {
      "name": "RateLimitingPlugin",
      "enabled": true,
      "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
      "configSection": "githubRateLimit"
    }
  ],
  "urlsToWatch": [
    "https://api.github.com/*"
  ],
  "githubRateLimit": {
    "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/ratelimitingplugin.schema.json",
    "headerLimit": "x-ratelimit-limit",
    "headerRemaining": "x-ratelimit-remaining",
    "headerReset": "x-ratelimit-reset",
    "resetFormat": "UtcEpochSeconds",
    "costPerRequest": 1,
    "rateLimit": 5,
    "resetTimeWindowSeconds": 60,
    "warningThresholdPercent": 0,
    "whenLimitExceeded": "Custom",
    "customResponseFile": "github-rate-limit-exceeded.json"
  }
}

Caution

Añada el RetryAfterPlugin antes del RateLimitingPlugin en su archivo de configuración. Si lo agrega después, el RateLimitingPlugin gestiona la solicitud antes de que el RetryAfterPlugin pueda comprobarla.

En el archivo de respuesta personalizado, defina la respuesta que GitHub devuelve cuando se supera el límite de tasa principal.

Archivo: github-rate-limit-exceeded.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/ratelimitingplugin.customresponsefile.schema.json",
  "statusCode": 429,
  "headers": [
    {
      "name": "content-type",
      "value": "application/json; charset=utf-8"
    }
  ],
  "body": {
    "message": "API rate limit exceeded for user ID 1.",
    "documentation_url": "https://docs.github.com/rest/overview/rate-limits-for-the-rest-api"
  }
}

Inicie el proxy de desarrollo y ejecute la aplicación.

devproxy --config-file devproxyrc.json

Dev Proxy reenvía las primeras 5 solicitudes de cada minuto a GitHub y establece los encabezados x-ratelimit-* en las respuestas. A partir de la 6.ª solicitud, Dev Proxy devuelve la respuesta de limitación de tasa con x-ratelimit-remaining establecida en 0 y x-ratelimit-reset establecida en el final de la ventana. Si la aplicación vuelve a llamar a la API antes de que se restablezca la ventana, se informa de ello mediante RetryAfterPlugin y se limita la solicitud.

Compruebe que su aplicación:

  • x-ratelimit-remaining detecta y reduce la velocidad antes de llegar a 0.
  • Detiene la llamada a la API después de una respuesta por límite de peticiones y espera hasta x-ratelimit-reset.
  • Indica al usuario lo que sucede, por ejemplo, "se ha alcanzado el límite de tasa de GitHub, reintentar a las 14:05", en lugar de fallar silenciosamente.

Note

GitHub devuelve 403 o 429 cuando se supera un límite de frecuencia. Para probar que la aplicación también controla 403 , cambie statusCode a 403. El RetryAfterPlugin solo realiza un seguimiento de las respuestas de 429, por lo que no notifica reintentos tempranos después de 403.

Tip

El proxy de desarrollo reenvía las solicitudes a GitHub hasta que se alcanza el límite simulado. Estas solicitudes también consumen tu límite real de solicitudes de GitHub.

Simular límites de tasa secundarios

Los límites de tasa secundarios vienen en ráfagas e incluyen un encabezado retry-after. Utiliza GenericRandomErrorPlugin para devolverlos de forma aleatoria.

Archivo: devproxyrc.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/rc.schema.json",
  "plugins": [
    {
      "name": "RetryAfterPlugin",
      "enabled": true,
      "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
    },
    {
      "name": "GenericRandomErrorPlugin",
      "enabled": true,
      "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
      "configSection": "githubSecondaryRateLimit"
    }
  ],
  "urlsToWatch": [
    "https://api.github.com/*"
  ],
  "githubSecondaryRateLimit": {
    "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/genericrandomerrorplugin.schema.json",
    "errorsFile": "github-secondary-rate-limit.json",
    "rate": 50,
    "retryAfterInSeconds": 60
  }
}

Archivo: github-secondary-rate-limit.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/genericrandomerrorplugin.errorsfile.schema.json",
  "errors": [
    {
      "request": {
        "url": "https://api.github.com/*"
      },
      "responses": [
        {
          "statusCode": 429,
          "headers": [
            {
              "name": "content-type",
              "value": "application/json; charset=utf-8"
            },
            {
              "name": "retry-after",
              "value": "@dynamic"
            }
          ],
          "body": {
            "message": "You have exceeded a secondary rate limit. Please wait a few minutes before you try again.",
            "documentation_url": "https://docs.github.com/rest/overview/rate-limits-for-the-rest-api#about-secondary-rate-limits"
          }
        }
      ]
    }
  ]
}

Inicie el proxy de desarrollo y ejecute la aplicación. Compruebe que la aplicación espera el número de segundos en el retry-after encabezado antes de llamar a la API de nuevo. Si no es así, RetryAfterPlugin lo notifica.

Si usa Octokit con el complemento de limitación, compruebe que los controladores onRateLimit y onSecondaryRateLimit se ejecutan y que devuelven el resultado esperado.

Paso siguiente

Más información sobre RateLimitingPlugin.

Consulte también