Testowanie sposobu obsługi przez aplikację limitów szybkości interfejsu API GitHub

Wskazówka

Nie znasz ograniczania przepustowości? Dowiedz się , czym jest ograniczanie przepustowości i jak go obsłużyć.

Na pierwszy rzut oka
Cel: Testowanie sposobu obsługi przez aplikację limitów liczby żądań interfejsu API REST GitHub
Czas: 15 minut
Plugins:RateLimitingPlugin, GenericRandomErrorPlugin, RetryAfterPlugin
Wymagania wstępne:konfigurowanie serwera proxy deweloperskiego

Aplikacja wywołuje interfejs API GitHub. Działa na Twojej maszynie, a potem zadanie CI, duża organizacja albo intensywny dzień sprawiają, że przekracza limit żądań i zaczyna kończyć się niepowodzeniem. Aby przetestować go względem rzeczywistego interfejsu API, musisz wyczerpać limit zapytań, a następnie poczekać do godziny, zanim będziesz mógł spróbować ponownie. Dev Proxy lokalnie symuluje limity liczby żądań GitHub, z limitem i przedziałem czasu, które wybierasz.

Dowiedz się, co zwraca GitHub

GitHub ma 2 rodzaje limitów liczby żądań dla interfejsu API REST.

Podstawowe limity szybkości ograniczają liczbę żądań wysyłanych na godzinę. Na przykład 60 dla nieuwierzytelnionych żądań i 5000 dla żądań z osobistym tokenem dostępu. Każda odpowiedź zawiera nagłówki pokazujące, gdzie jesteś:

Header Meaning
x-ratelimit-limit Maksymalna liczba żądań na godzinę
x-ratelimit-remaining Liczba żądań pozostawionych w bieżącym oknie
x-ratelimit-reset Czas resetowania okna w sekundach epoki UTC

Po przekroczeniu limitu podstawowego GitHub zwraca 403 lub 429, z ustawionym x-ratelimit-remaining na 0. Nie ponawiaj próby do czasu wskazanego w x-ratelimit-reset.

Pomocnicze limity szybkości chronią GitHub przed wybuchami, takimi jak zbyt wiele współbieżnych żądań lub zbyt duża ilość zawartości. Po przekroczeniu jednego z limitów GitHub zwraca 403 lub 429 z komunikatem o dodatkowym limicie szybkości. Jeśli odpowiedź ma retry-after nagłówek, poczekaj tyle sekund. W przeciwnym razie poczekaj co najmniej minutę i zwiększ czas oczekiwania, jeśli żądanie zakończy się niepowodzeniem.

GitHub mogą blokować integracje, które nadal wysyłają żądania, gdy są one ograniczone. Aby uzyskać więcej informacji, zobacz Limity szybkości interfejsu API REST w dokumentacji GitHub.

Symuluj podstawowy limit szybkości żądań

Użyj RateLimitingPlugin, aby zliczyć żądania i zwrócić nagłówki limitu szybkości GitHub. Aby przetestować bez oczekiwania na godzinę, użyj małego limitu i krótkiego okna.

Plik: 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

Dodaj element RetryAfterPlugin przed elementem RateLimitingPlugin w pliku konfiguracji. Jeśli dodasz to później, RateLimitingPlugin obsłuży żądanie, zanim RetryAfterPlugin będzie mógł to sprawdzić.

W pliku odpowiedzi niestandardowej zdefiniuj odpowiedź, którą GitHub zwraca po przekroczeniu podstawowego limitu szybkości.

Plik: 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"
  }
}

Uruchom Dev Proxy i uruchom aplikację.

devproxy --config-file devproxyrc.json

Dev Proxy przekazuje pierwsze 5 żądań w każdej minucie do GitHub i ustawia nagłówki x-ratelimit-* w odpowiedziach. Od 6. żądania serwer proxy dewelopera zwraca odpowiedź o limicie szybkości z x-ratelimit-remaining ustawionym na 0 i x-ratelimit-reset ustawionym na koniec okna. Jeśli aplikacja ponownie wywołuje interfejs API przed zresetowaniem okna, RetryAfterPlugin zgłasza to i ogranicza żądanie.

Sprawdź, czy Twoja aplikacja:

  • Odczytuje x-ratelimit-remaining i spowalnia, zanim osiągnie 0.
  • Zatrzymuje wywoływanie interfejsu API po odpowiedzi o przekroczeniu limitu żądań i czeka na x-ratelimit-reset.
  • Informuje użytkownika o tym, co się dzieje, na przykład „osiągnięto limit żądań GitHub, ponawianie próby o godzinie 14:05”, zamiast kończyć się po cichu niepowodzeniem.

Note

GitHub zwraca wartość 403 lub 429 po przekroczeniu limitu liczby żądań. Aby przetestować, czy aplikacja obsługuje też 403, zmień wartość statusCode na 403. Tylko RetryAfterPlugin śledzi 429 odpowiedzi, więc nie zgłasza wczesnych ponownych prób po .403

Wskazówka

Serwer proxy deweloperów przekazuje żądania do GitHub do momentu osiągnięcia symulowanego limitu. Te żądania są również liczone względem rzeczywistego limitu szybkości GitHub.

Symulowanie limitów szybkości pomocniczej

Wtórne limity liczby żądań występują seriami i zawierają nagłówek retry-after. Użyj metody GenericRandomErrorPlugin , aby zwrócić je losowo.

Plik: 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
  }
}

Plik: 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"
          }
        }
      ]
    }
  ]
}

Uruchom serwer proxy deweloperów i uruchom aplikację. Sprawdź, czy aplikacja czeka przez liczbę sekund podaną w nagłówku retry-after, zanim ponownie wywoła interfejs API. Jeśli tak nie jest, RetryAfterPlugin to raportuje.

Jeśli używasz biblioteki Octokit z wtyczką ograniczania przepustowości, sprawdź, czy onRateLimit procedury obsługi i onSecondaryRateLimit procedury obsługi działają i że zwracają oczekiwany wynik.

Następny krok

Dowiedz się więcej o pliku RateLimitingPlugin.

Informacje dodatkowe