Retry-After は、次の要求を送信するまでの待機時間をアプリに伝える HTTP 応答ヘッダーです。 値は秒数または HTTP 日付です。 API から送信された場合は、リクエストを拒否したサーバーから送信されるため、「いつ再試行できるか」に対する最も信頼性の高い回答になります。 詳細については、 RFC 9110 セクション 10.2.3 を参照してください。
Retry-After の見え方
ヘッダーには 2 つの形式があります。 アプリで両方を処理する必要があります。
| Format | Example | 意味 |
|---|---|---|
| Seconds | Retry-After: 120 |
応答を取得してから 120 秒 (2 分) 待ちます。 値は非負の整数です。 |
| HTTP 日付 | Retry-After: Fri, 31 Dec 1999 23:59:59 GMT |
この時刻より前に要求を再度送信しないでください。 日付は常に GMT です。 |
サーバーは、これらの状態コードで Retry-After を送信します。
| Status |
Retry-Afterの意味 |
Source |
|---|---|---|
429 Too Many Requests |
新しい要求を送信するまでの待機時間。 サーバーにそれが含まれる場合があります。 | RFC 6585、セクション 4 |
503 Service Unavailable |
サービスを利用できないことが見込まれる期間。 サーバーにそれが含まれる場合があります。 | RFC 9110、セクション 15.6.4 |
413 Content Too Large |
条件が一時的な場合、サーバーは、どのくらいで解消されるかを示す必要があります。 | RFC 9110、セクション 15.5.14 |
任意の 3xx リダイレクト |
リダイレクトに従う前に待機する最小時間。 | RFC 9110、セクション 10.2.3 |
ヘッダーは省略可能です。 一部の API では、代わりに独自のヘッダーが使用されます。 たとえば、GitHubは、制限がいつリセットされるかを x-ratelimit-reset で知らせてくれます。 詳細については、「GitHub API のレート制限の超過」を参照してください。
Retry-After を処理する方法
- 両方の形式を読み取ります。 値が数値の場合は秒です。 それ以外の場合は、日付として解析し、現在の時刻を減算します。 日付が既に過去の場合は、すぐに再試行できます。
- 少なくともヘッダーに表示される時間は待機します。 早めに再試行すると、通常、別の
429または503が返されます。 一部の API では、スロットリングされている間も要求がカウントされ続けるので、早期の再試行によって待機時間が長くなる可能性があります。 たとえば、「Microsoft Graph のスロットリングに関するガイダンス」を参照してください。 - ヘッダーが見つからない場合は、ジッター付きバックオフにフォールバックします。 試行が失敗するたびに待機を 2 倍にし、多数のクライアントが同時に再試行しないようにランダムな量を追加し、待機を上限にします。
- 再試行回数を制限してください。 数回試行した後、エラーを呼び出し元に返します。
- 再試行が役に立つかどうかを確認します。 一部の API は、クレジットや支出制限を使い切ったときに
429を返します。 待っていても解決しません。 例については、「 OpenAI のinsufficient_quotaとcredit_balance_exhausted」を参照してください。
function retryDelayMs(response, attempt) {
const value = response.headers.get('retry-after');
if (value) {
const seconds = Number(value);
const ms = Number.isNaN(seconds) ? Date.parse(value) - Date.now() : seconds * 1000;
if (!Number.isNaN(ms)) {
return Math.max(ms, 0);
}
}
// No usable header: exponential backoff with jitter, capped at 30 seconds
return Math.random() * Math.min(30_000, 1_000 * 2 ** attempt);
}
人気のある SDK でできること
多くの SDK は Retry-After を処理しますが、再試行回数を使い切るまでの間のみ処理します。 すると、コードでエラーが発生します。
| SDK | 既定での動作 |
|---|---|
| .NET 標準の回復性ハンドラー | 指数バックオフとジッターを使用して、 408、 429、および 5xx 応答を最大 3 回再試行します。
true は既定で Retry-After になるため、遅延には ShouldRetryAfterHeader が使用されます。 |
| Microsoft Graph SDKs |
Retry-Afterが存在する場合は使用し、存在しない場合は指数バックオフにフォールバックします。 JSON バッチ内の要求は自動的には再試行されません。 |
| OpenAI Python SDK | 接続エラーと 408、 409、 429、および 5xx 応答を短い指数バックオフで 2 回再試行します。
max_retries を設定して変更します。 |
SDK のドキュメントで正確なポリシーを確認し、最後の再試行が失敗した後に何が起こるかをテストしてください。
アプリが Retry-After を処理することをテストする方法
開発中に Retry-After が発生することはほとんどなく、発生したとしても、その値を制御することはできません。 そのため、これをテストする方法によって、ユーザーよりも先にバグを見つけられるかどうかが決まります。
| Approach | 見つけたもの | 欠落しているもの |
|---|---|---|
| 運用環境の待機 | 実際のエラー | すべて、ユーザーがクリックするまで |
| テストで API をモックするか、コーディング エージェントにモックを記述させる | コードがヘッダーを解析するかどうか | 実際の HTTP クライアントまたは SDK が十分に長く待機しているかどうか、および API が実際に何を送信するか。 アプリでは、モックに到達するためにテスト専用のスイッチも必要です。 |
| レート制限されるまで実際の API を呼び出す | 実際の動作 | オンデマンドでスロットリングされた応答をトリガーすることはできません。実際のクォータを消費します |
| アプリの実際のトラフィックをインターセプトし、オンデマンドでスロットルされた応答を返す | 実際の SDK と再試行ポリシーがヘッダーが示す時間どおりに待機するかどうか | アプリ自体には何の変化もないため、コードを単独でテストすることにはなりません。 それ用に単体テストを取っておいてください。 |
アプリで試す
Dev Proxy は、選択した API に対するアプリの要求をインターセプトし、429 応答を Retry-After ヘッダーとともに返しますが、アプリは実際の URL を呼び出し続けます。
RetryAfterPlugin は、スロットリングされた各リクエストが再試行されるタイミングを記憶します。 アプリがその時刻より前に同じ URL を呼び出した場合、Dev Proxy はそれを報告し、要求を再度スロットルします。 プラグインは 429 応答のみを追跡します。
GenericRandomErrorPlugin のエラー ファイルで、429 応答の Retry-After 値を @dynamic に設定すると、Dev Proxy が秒数を自動的に入力し、それを追跡します。
これを試すには、両方のプラグインを使用するプリセットをダウンロードし、それを使用して Dev Proxy を起動します。
devproxy config get openai-throttling
devproxy --config-file "~dataFolder/configs/openai-throttling/.devproxy/devproxyrc.json"
その後、通常どおりにアプリを実行し、どのように動作するかを確認します。 Dev Proxy をインストールするには、「Dev Proxy のセットアップ」を参照してください。
次のステップ
参照
Dev Proxy