GitHub API 속도 제한이 초과됨: 의미 및 처리 방법

GitHub 앱에서 보낼 수 있는 REST API 요청 수를 제한합니다. 한도를 초과하면 GitHub는 한도가 다시 설정되거나 대기 시간이 지날 때까지 429 또는 403 상태로 요청을 거부합니다. GitHub 시간당 요청에 대한 기본 제한과 버스트로부터 보호하는 보조 제한의 두 가지 제한이 있습니다. 앱이 속도 제한이 적용되는 동안 요청을 계속 보내는 경우 GitHub에서 통합을 금지할 수 있습니다. 자세한 내용은 REST API에 대한 속도 제한을 참조하세요.

GitHub의 요청 제한 살펴보기

Limit 가치 검토할 때
기본, 인증되지 않음 IP 주소당 시간당 60개 요청 403 또는 429, 및 x-ratelimit-remaining는 0입니다
주 개인용 액세스 토큰 시간당 5,000개 요청 위와 동일
기본, GITHUB_TOKEN GitHub Actions에서 리포지토리당 시간당 1,000개 요청 위와 동일
보조 예를 들어 동시 요청은 최대 100개, REST 엔드포인트의 경우 분당 900포인트, 콘텐츠 생성 요청은 분당 약 80개 403 또는 429 오류 메시지와 함께 표시됩니다. retry-after 가 있을 수 있습니다.

GitHub 예고 없이 보조 제한을 변경할 수 있으며, 이 제한에 얼마나 근접했는지 확인할 수 있는 방법은 없습니다.

모든 응답에는 기본 제한 대비 현재 상태를 알려주는 헤더가 포함됩니다.

Header 그것은 당신에게 무엇을 알려줍니다
x-ratelimit-limit 시간당 보낼 수 있는 최대 요청 수
x-ratelimit-remaining 현재 창에 남아 있는 요청 수
x-ratelimit-used 현재 창에서 보낸 요청 수
x-ratelimit-reset 윈도우가 다시 설정되면 UTC epoch 초 단위로
x-ratelimit-resource 요청이 계산되는 한도

GitHub 속도 제한을 처리하는 방법

  1. 속도 제한과 권한 오류를 구분합니다. 토큰에 액세스 권한이 없으면 GitHub도 403를 반환합니다. 응답에 retry-after가 없고 x-ratelimit-remaining이 0이 아니며 메시지에 속도 제한이 언급되지 않는 경우 권한 문제입니다. 다시 시도하지 마세요.
  2. 먼저 retry-after을(를) 선택하세요. 헤더가 있으면 헤더에 지정된 초 수만큼 기다립니다.
  3. 그렇지 않으면 재설정을 기다리세요. 0이(가) x-ratelimit-remaining인 경우 x-ratelimit-reset의 시간까지 다시 시도하지 마세요.
  4. 그렇지 않으면 1분 이상 기다리세요. 헤더가 둘 다 없는 보조 제한의 경우 GitHub에서는 1분 이상 기다리도록 요청하며, 재시도가 실패할 때마다 더 오래 기다리도록 요청합니다. 설정된 재시도 횟수 후에 중지하고 오류를 발생시킵니다.
  5. 소진되기 전에 속도를 늦추어 보세요.x-ratelimit-reset와 x-ratelimit-remaining를 사용해 요청 속도를 조절하세요. 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 요청 제한에 거의 도달하지 않습니다. 몇 건만 요청을 보내도 시간당 5,000개는 무한한 것처럼 느껴집니다. 따라서 속도 제한 처리를 테스트하는 방법은 사용자가 버그를 발견하기 전에 버그를 찾을 수 있을지를 결정합니다.

Approach 찾은 내용 당신이 놓친 것
프로덕션을 기다리세요 실제 실패 사용자가 그것을 누를 때까지 모든 것
테스트에서 API를 모의하거나 코딩 에이전트가 모의 개체를 작성하도록 허용하세요 재시도 분기 실행 여부 GitHub의 실제 헤더와 오류 본문, 그리고 SDK의 재시도 정책 또한 모의 객체에 도달하려면 앱에 테스트 전용 스위치가 필요합니다.
제한될 때까지 실제 API를 호출하세요 실제 동작 최대 5,000개의 요청이 소요될 수 있으며, 요청 시 보조 제한을 트리거할 수 없으며 통합이 금지될 위험이 있습니다.
앱의 실제 트래픽을 가로채고 요청 시 속도 제한 응답을 반환하세요. 실제 URL, 실제 SDK 및 재시도 정책, GitHub 자체 헤더 및 오류 형식 앱에서 아무것도 변경되지 않으므로 코드가 격리된 상태로 테스트되지 않습니다. 그건 단위 테스트로 검증하세요.

앱에서 직접 써보기

Dev Proxy는 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와 함께 Dev Proxy를 시작합니다. 보조 속도 제한을 retry-after 헤더와 함께 429 임의로 반환합니다.

그런 다음 평소와 같이 앱을 실행하고 어떻게 동작하는지 확인합니다. 개발 프록시를 설치하려면 개발 프록시 설정을 참조하세요.

다음 단계

또한, 다음을 참조하세요.