GitHub API のレート制限を超えました: その意味と対処方法

GitHubは、アプリが送信できる REST API 要求の数を制限します。 制限を超えると、GitHubは、制限がリセットされるか待機時間が経過するまで、403または429ステータスでリクエストを拒否します。 GitHubには 2 種類の制限があります。1 時間あたりの要求に対する主な制限と、急増を防ぐセカンダリ制限です。 レート制限されている間もアプリがリクエストを送信し続けると、GitHub があなたのインテグレーションを禁止する可能性があります。 詳細については、「REST API のレート制限」を参照してください。

GitHubのレート制限とは

Limit Value それを確認するとき
主, 認証されていない 1 時間あたり、IP アドレスあたり 60 件の要求 403 または 429、 x-ratelimit-remaining が 0
メイン、個人用アクセス トークン 1 時間あたり 5,000 件の要求 同上
GitHub Actions の GITHUB_TOKEN プライマリ 1 リポジトリあたり 1 時間ごとに 1,000 リクエスト 同上
Secondary たとえば、同時要求数は 100 個以下、REST エンドポイントの場合は 1 分あたり 900 ポイント、コンテンツ生成要求数は 1 分あたり約 80 個です。 403 またはエラー メッセージ付きの 429。 retry-after が存在する可能性があります。

GitHubは、予告なしにセカンダリの制限を変更できます。また、その制限にどの程度近づいているかを確認する方法はありません。

すべての応答には、プライマリ制限の現在の使用状況を示すヘッダーが含まれています。

Header それがあなたに伝えるもの
x-ratelimit-limit 1 時間あたりに送信できるリクエストの最大数
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レート制限に達することはめったにありません。 いくつかの要求を送信すると、1時間あたり5,000件が無限にあるように感じられます。 そのため、レート制限の処理をテストする方法によって、ユーザーが見つける前にバグが見つかるかどうかを決めます。

Approach 見つけたもの 見逃したもの
本番環境を待つ 実際の失敗 ユーザーがそれを押すまでのすべて
テストで API をモックするか、コーディング エージェントにモックを記述させる 再試行ブランチを実行するかどうか GitHubの実際のヘッダーとエラー本文、および SDK の再試行ポリシー。 アプリでは、モックに到達するためにテスト専用のスイッチも必要です。
制限されるまで実際のAPIを呼び出してください 実際の動作 最大 5,000 件のリクエストがかかります。必要に応じて 2 次的な制限をトリガーすることはできません。統合が禁止されるおそれがあります
アプリの実際のトラフィックをインターセプトし、要求に応じてレート制限の応答を返します 実際の URL、実際の SDK と再試行ポリシー、GitHub独自のヘッダーとエラー形式 アプリ内では何も変更されないため、コードを独立した状態でテストするわけではありません。 そのための単体テストは残しておいてください。

アプリで試す

Dev Proxyは、アプリのapi.github.comへの要求をインターセプトし、GitHubスタイルのレート制限応答を返しますが、アプリは実際のURLを呼び出し続けます。 github-rate-limitingプリセットでは、リクエストは 1 時間あたり 60 回の上限としてカウントされ、x-ratelimit-* ヘッダーを送信し、上限に達すると 429 を含む API rate limit exceeded を返します。それまでは、リクエストは GitHub に送られ、実際の上限に対してもカウントされます。

プリセットをダウンロードし、それを使用して開発プロキシを起動します。

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 ヘッダーを伴ってランダムに返します。

その後、通常どおりにアプリを実行し、アプリがどのように動作するかを確認します。 開発プロキシをインストールするには、「 開発プロキシの設定」を参照してください。

次のステップ

参照