превышен лимит запросов GitHub API: что это означает и как с этим справиться.

GitHub ограничивает количество запросов REST API к приложению. При превышении лимита GitHub отклоняет ваши запросы со статусом 403 или 429, пока лимит не сбросится или не истечет время ожидания. GitHub имеет 2 типа ограничений: основное ограничение запросов в час и вторичные ограничения, которые защищают от всплесков. Если приложение продолжает отправлять запросы, пока он ограничен, GitHub может запретить интеграцию. Дополнительные сведения см. в разделе ограничения частоты запросов для REST API.

Как выглядят лимиты запросов GitHub

Limit Value Когда вы просматриваете это
Основной, неаутентифицированный 60 запросов в час для IP-адреса 403 или 429, и x-ratelimit-remaining есть 0
Первичный, личный токен доступа 5000 запросов в час То же, что и выше
Главный, GITHUB_TOKEN в GitHub Actions 1000 запросов в час на репозиторий То же, что и выше
Secondary Например, не более 100 одновременных запросов, 900 точек в минуту для REST-эндпоинтов и около 80 запросов, генерирующих контент, в минуту 403 или 429 с сообщением об ошибке. retry-after может присутствовать.

GitHub может изменять вторичные ограничения без уведомления, и нет способа проверить, насколько вы близки к ним.

Каждый ответ содержит заголовки, которые сообщают вам, насколько вы приблизились к основному лимиту:

Header Что это говорит вам
x-ratelimit-limit Максимальное количество запросов в час
x-ratelimit-remaining Сколько запросов осталось в текущем окне
x-ratelimit-used Количество отправленных запросов в текущем окне
x-ratelimit-reset При сбросе окна — в секундах эпохи UTC
x-ratelimit-resource Какое ограничение применяется к запросу

Как справиться с лимитом запросов GitHub

  1. Отличайте лимит запросов от ошибки прав доступа. GitHub также возвращает 403, когда у вашего маркера нет доступа. Если в ответе нет retry-after, x-ratelimit-remaining не является 0, и в сообщении не упоминается лимит запросов, это проблема с правами доступа. Не пытайтесь снова.
  2. Сначала следуйте retry-after. Если заголовок присутствует, подождите столько секунд.
  3. В противном случае дождитесь сброса. Если x-ratelimit-remaining — это 0, не повторяйте попытку до времени, указанного в x-ratelimit-reset.
  4. В противном случае подождите не менее 1 минуты. Для вторичного ограничения без какого-либо из этих заголовков GitHub просит вас ждать не менее 1 минуты и ждать дольше после каждой неудачной попытки. Остановите после заданного числа повторных попыток и выдайте ошибку.
  5. Снизьте скорость, прежде чем исчерпаете лимит. Используйте x-ratelimit-remaining и x-ratelimit-reset, чтобы регулировать темп запросов. Не создавайте логику вокруг точного оставшегося количества, так как GitHub может изменить ограничения. Заголовки x-ratelimit-* являются источником истины, а не GET /rate_limit эндпоинтом.
async function githubWaitMs(response, attempt) {
  if (response.status !== 403 && response.status !== 429) {
    return null;
  }
  const retryAfter = response.headers.get('retry-after');
  if (retryAfter) {
    return Number(retryAfter) * 1000;
  }
  if (response.headers.get('x-ratelimit-remaining') === '0') {
    const resetMs = Number(response.headers.get('x-ratelimit-reset')) * 1000;
    return Math.max(resetMs - Date.now(), 0);
  }
  const { message = '' } = await response.clone().json().catch(() => ({}));
  if (response.status === 429 || /rate limit/i.test(message)) {
    return 60_000 * 2 ** attempt;
  }
  // A 403 without rate limit signals is a permission problem: don't retry
  return null;
}

Вызывающий объект повторяет попытку, когда функция возвращает число, и прекращает попытки после нескольких повторов.

Проверка того, что приложение обрабатывает лимиты запросов GitHub

Во время разработки вы редко упираетесь в лимит запросов GitHub. Вы отправляете несколько запросов, и лимит в 5000 запросов в час кажется бесконечным. Таким образом, способ тестирования обработки ограничения частоты запросов решает, найдёте ли вы ошибки до того, как их найдут ваши пользователи.

Approach Что вы найдете Что вы пропустили
Дождитесь production Реальные сбои Всё — до тех пор, пока пользователь не нажмёт на это
Имитируйте API в тестах или позвольте агенту для написания кода написать мок Выполняется ли ветвь повторных попыток Реальные заголовки и тела ошибок GitHub, а также политика повторных попыток вашего SDK. Приложению также требуется переключатель только для тестирования, чтобы достичь мока.
Вызывайте реальный API до тех пор, пока он не начнет ограничивать вас Реальное поведение Требуется до 5 000 запросов, вы не можете активировать дополнительное ограничение по запросу, и вы рискуете запретом на интеграцию.
Перехватывайте реальный трафик приложения и по запросу возвращайте ответы о превышении лимита запросов Реальные URL-адреса, ваш реальный SDK и политика повторных попыток, а также собственные заголовки и формат ошибок GitHub Ничего в приложении не изменяется, поэтому код не проверяется изолированно. Оставьте модульные тесты для этого.

Попробуйте его в вашем приложении

Прокси-сервер разработки перехватывает запросы вашего приложения к api.github.com и возвращает ответы GitHub с ограничением частоты запросов, в то время как ваше приложение продолжает вызывать реальные URL-адреса. Предустановка github-rate-limiting засчитывает ваши запросы в лимит 60 в час, отправляет заголовки x-ratelimit-* и возвращает 429 с API rate limit exceeded, когда лимит исчерпан. До тех пор ваши запросы отправляются в GitHub и также засчитываются в ваш реальный лимит.

Скачайте предустановленный набор и запустите с ним Dev Proxy:

devproxy config get github-rate-limiting
devproxy --config-file "~dataFolder/configs/github-rate-limiting/.devproxy/devproxyrc.json"

Чтобы протестировать вторичные ограничения, вместо этого запустите прокси-сервер разработки с devproxyrc-secondary.json из той же папки. Он случайным образом возвращает дополнительное ограничение 429 скорости с заголовком retry-after .

Затем запустите приложение как обычно и посмотрите, что оно делает. Чтобы установить Dev Proxy, см. статью Настройка Dev Proxy.

Дальнейшие действия

См. также