生成AI APIのレート制限・再試行・エラー処理では、HTTP状態とerror.codeを先に分類し、再試行できる失敗だけに回数と時間の上限を設けます。 本記事では、429、5xx、タイムアウトを切り分け、重複実行と無限再試行を防ぐ本番設計を示します。
生成AI APIのレート制限・再試行エラーを最初の10分で切り分ける
最初に、利用者が見た文言ではなくHTTP状態、error.code、OpenAIのリクエストID、要求時刻、Project、モデル、入力・出力トークン、試行番号を一件分そろえます。429でも、短時間の要求数超過、トークン量超過、クレジット不足、組織・Projectの利用額上限では対処が異なります。401や403、500や503、クライアント側タイムアウトを429と同じ再試行へ入れてはいけません。
OpenAIのRate limits公式資料は、上限・残量・回復時間を示すx-ratelimit-*ヘッダーを説明しています。要求数とトークン量には別の残量とリセット時刻があるため、両方を記録します[1]。ヘッダーを取得できないネットワーク切断では、直前の同一Projectの観測値と自社キューを使い、推測で大量再送しません。
10分間の確認順:1. HTTP状態と error.code を保存する2. trace_id と x-request-id を結び付ける3. remaining-requests と remaining-tokens を比べる4. 同時刻の流量、再試行数、入力長を確認する5. 副作用のある処理なら再送前に完了状態を照会する6. 認証・利用額上限・データ事故なら自動復旧を止める
利用者から「遅い」とだけ報告された場合は、接続前、最初の応答まで、生成中、後続保存のどこで時間を使ったかを分けます。自社タイムアウトが15秒でOpenAIから16秒後に完了した場合、単純再送すると同じ処理が二本走ります。特にメール送信やデータ更新を伴うワークフローでは、再試行より先に冪等性と処理状態を確認します。
429・401・5xx・タイムアウトの原因表
原因頻度はサービスごとに違うため、「429が多いはず」と決め打ちしません。直近30日の全失敗をHTTP状態、エラーコード、モデル、Project、時間帯、入力トークン帯で集計し、障害件数だけでなく要求総数に対する率を出します。次の優先度は初期調査の目安であり、自社の実測値へ置き換えます。
| 分類 | 初期優先度 | 識別する情報 | 同じ要求の再試行 |
|---|---|---|---|
| 要求数の429 | 高 | remaining-requestsが少なく、requestsのresetが近い | resetとジッターを考慮して上限内で行う |
| トークン量の429 | 高 | remaining-tokensが不足し、長い入力や並列処理が集中 | 入力縮小かキュー待ち後に行う |
| 利用額・クレジットの429 | 中 | error.codeが上限や残高を示す | 設定変更まで行わない |
| 401・403 | 中 | 失効キー、Project違い、権限、許可IP | 自動では行わない |
| 500・503 | 中 | 同時刻に複数入力で発生し、状態ページとも照合 | 短い待機後に限定回数で行う |
| 自社タイムアウト | 高 | 上流完了前にプロキシやジョブ期限が切れる | 処理状態を確認してから判断する |
| 入力エラーの400 | 中 | 固定入力で再現し、形式・上限・パラメータが不正 | 入力を直すまで行わない |
OpenAIの公式エラー資料は、429をレート制限、クレジット不足、組織・Projectの利用額上限などに分け、401もキー、組織、Project、許可IPに関する原因を示しています[2]。したがって再試行ライブラリへ渡す前に、statusとerror.codeを組み合わせて分類します。未知コードは一時障害として無条件再送せず、失敗キューへ保留して担当者が確認します。
原因別の再試行と流量制御
要求数の429は回復時刻まで送信間隔を広げる
要求数の残量が先に尽きたら、並列数を下げ、キューから一定速度で取り出します。全ワーカーが同時に再送しないよう、待機へ乱数を加えます。OpenAIのRate limits資料はランダムな指数バックオフを案内し、失敗した要求も分単位の制限へ数えられるため連続再送は効かないと説明しています[1]。
トークン量の429は入力長と同時実行を下げる
一件の入力が長い場合は、不要な履歴や重複文書を外し、出力上限を業務に必要な長さへ調整します。複数の長文要求が重なる場合は、推定トークンで重み付けしたキューを使い、小さい要求だけを先に流して大きい要求を飢餓状態にしないよう優先度と最大待ち時間を持たせます。要求数の空きがあってもトークン残量が足りなければ送信しません。
5xxは総時間と試行回数の両方を制限する
一時的な500や503は再試行候補ですが、業務期限を超える復旧は成功ではありません。たとえば一回8秒の上限、最大3回、全体20秒を再試行予算にします。1秒、2秒、4秒という固定列ではアクセスがそろうため、各上限内でランダムに待ちます。予算を使い切った要求はデッドレターへ移し、バックグラウンドで無限に回しません。
async function callWithBudget(run, classify) { const started = Date.now(); const budgetMs = 20_000; for (let attempt = 1; attempt <= 3; attempt += 1) { try { return await run({ timeoutMs: 8_000, attempt }); } catch (error) { const kind = classify(error); const elapsed = Date.now() - started; if (!kind.retryable || attempt === 3 || elapsed >= budgetMs) throw error; const ceiling = Math.min(4_000, 500 * 2 ** (attempt - 1)); const delay = Math.floor(Math.random() * ceiling); if (elapsed + delay > budgetMs) throw error; await new Promise((resolve) => setTimeout(resolve, delay)); } }}
401・403・利用額上限は自動再試行しない
認証失敗は、別のAPIキーを順番に試すフォールバックで隠しません。資格情報はサーバーの鍵管理から取得し、Projectと環境を固定します。失効、権限、許可IP、残高、利用額上限を所有者が確認するまで該当キューを停止します。入力不正の400も、同じ内容の再送では直らないため、利用者または呼び出し元へ修正可能な項目を返します。
冪等性と待ち行列で再発を防ぐ
再試行で最も危険なのは、最初の処理が成功したか不明なまま副作用を重ねることです。自社の業務要求ごとに冪等性キーを発行し、received、calling_api、api_completed、side_effect_pending、done、failedを保存します。同じキーが再到着したら、新しいAPI呼び出しを作る前に既存状態を返します。メール送信やCRM更新はAPI応答の生成と別ジョブにし、完了済み副作用を二度実行しません。
待ち行列には最大長、優先度、最長待ち時間、同時実行数、デッドレター条件を設定します。キューが上限に達したら受け付け続けず、利用者へ混雑と再開見込みを返します。短時間の急増を平準化できても、日次需要が恒常的に上限を超える場合は、モデル・Projectの制限、処理設計、契約上の需要を見直します。キューは容量不足を永久に隠す装置ではありません。
| 記録 | 必須項目 | 判断に使う場面 |
|---|---|---|
| 要求台帳 | 冪等性キー、状態、試行番号、業務期限 | 再送前に処理済みか確認する |
| API試行 | モデル、Project、トークン、HTTP状態、request ID | 上流障害と入力問題を分ける |
| 流量 | キュー長、同時実行、残量、reset時刻 | 送信を続けるか停止する |
| 副作用 | 対象、承認者、実行時刻、結果ID | 二重更新と未実行を確認する |
OpenAIの本番運用資料は、ステージングと本番のProjectを分離し、Projectごとに利用者アクセス、レート、利用額上限を管理する考え方を示しています[4]。負荷試験を本番Projectへ混ぜず、ステージングで上限到達と復旧を再現します。本番の上限変更はアプリ担当だけで行わず、予算責任者と基盤運用が承認します。
自力対応を止める条件
資格情報が漏えいした疑い、異なる顧客の要求が混ざった疑い、送信・更新・課金が二重に起きた疑いは、再試行設定の調整で済ませません。該当キューと資格情報を停止し、情報セキュリティ、業務責任者、法務・個人情報保護担当へ引き継ぎます。影響を確認するまでログの削除や要求の一括再送を行わず、要求台帳と副作用の結果IDを保全します。
次の場合も、アプリ担当だけで継続を決めません。組織またはProjectの利用額上限へ達した、上限緩和が予算を超える、429が複数サービスへ波及した、状態不明の要求が10件以上ある、デッドレターが業務期限内に処理できない、OpenAIのリクエストIDと自社トレースを結び付けられない場合です。利用額は予算責任者、共通基盤は基盤運用、顧客影響は業務責任者が判断します。
OpenAIへの問い合わせが必要なときは、APIキーや個人情報を送らず、発生時刻、モデル、エンドポイント、HTTP状態、エラーコード、x-request-idまたはX-Client-Request-Id、再現頻度を整理します。公式APIリファレンスは本番トラブル調査のためリクエストIDの記録を推奨しています[3]。IDを取得できなかったタイムアウトでも、自社で付与したクライアント要求IDが調査の手掛かりになります。
再試行してよい要求を判定表で分ける
自動再試行へ入れる条件は、HTTP状態、処理の副作用、冪等性台帳、業務期限の四つです。読み取り専用の要約生成が一度失敗した場合と、生成結果を使って請求書を送信した後に応答だけ失われた場合を同じ設定へ入れてはいけません。後者は上流処理が成功済みの可能性があるため、状態を照会できるまで「不明」として隔離します。API呼び出しとメール送信などの副作用は別トランザクションに分け、結果IDを保存してから次段階へ進めます。
| 観測した状態 | 自動再試行 | 待機・確認 | 最終処置 |
|---|---|---|---|
| 429かつ要求残量不足 | reset後、最大3回 | キュー全体の同時実行を下げる | 期限超過前に低優先度を延期 |
| 500・503、応答本文なし | 乱数付き指数バックオフで最大2回 | 同じ障害が他モデルにもあるか確認 | 連続失敗で回路遮断 |
| 接続断、上流の成否不明 | 台帳照会まで禁止 | 冪等性キーと結果IDを照合 | 未実行だけを手動再送 |
| 400・401・403 | 禁止 | 入力、Project、秘密情報を修正 | 修正後は新規要求として送信 |
| 安全審査・業務規則で拒否 | 禁止 | 担当者が入力と利用目的を確認 | 業務側の判断を記録して終了 |
実装では、要求IDをキーにaccepted、running、succeeded、failed、unknownを保存します。ワーカーはsucceededを再実行せず、unknownを通常キューへ戻しません。再送回数だけでなく、初回時刻と次回予定時刻も残します。これにより、プロセス再起動やワーカー交代の後も上限回数が初期化されません。
再試行ストームを止めるしきい値
障害時に全ワーカーが同じ間隔で再送すると、回復しかけたAPIへ負荷が集中します。各要求の待機時間へ乱数を加え、サービス全体では「再試行予算」を設けます。想定例として、通常1分当たり600件のシステムなら、再試行を新規要求の20%以内、同時実行を平常時の50%以内に抑えます。過去5分の再試行増幅率が1.2を超えた場合は、新規の低優先度要求を受け付けても送信せず、キューで待たせます。
回路遮断の開始条件は、同一モデルで直近50件中25件以上が500系、429が3分連続、P95待ち時間が業務SLOの80%を超過、または1時間の推定費用が日次予算の25%を超えた場合です。いずれか一つで自動送信を止めます。解除は時間経過だけに任せず、5件の試験要求を1件ずつ送り、成功率100%、P95が平常値の1.5倍以内、重複処理0件を満たしたときに限ります。
自動再試行を採用しないケース
銀行振込、発注確定、顧客への外部送信など、二重実行を照会・取消できない処理には自動再試行が向きません。APIの結果を人が確認してから副作用を実行するか、副作用側が一意キーを受け付ける仕組みを先に用意します。要求ID、試行履歴、費用を保存できない環境も対象外です。障害を早く隠す設定より、状態不明を確実に止める設計を優先します。
復旧を費用と性能の評価票で判定する
成功率だけが戻っても、待ち時間と費用が悪化したままなら復旧とは扱えません。計測単位は論理的な業務要求とし、API試行回数を別列に持ちます。「再試行後成功率」は再試行対象のうち期限内に完了した要求の割合、「増幅率」は全API試行数を論理要求数で割った値です。費用は入力・キャッシュ済み入力・出力の各トークンへ利用モデルの単価を掛け、失敗応答を含む全試行で合算します。
| 評価項目 | 合格線の想定例 | 不合格時の動き |
|---|---|---|
| 期限内完了率 | 99.0%以上 | 低優先度受付を止め、残件の期限を再設定 |
| 再試行増幅率 | 1.10以下 | 最大試行数と同時実行を引き下げる |
| P95総所要時間 | 平常時の1.5倍以内 | キュー滞留とreset時刻を再確認 |
| 1要求当たり費用 | 直近28日中央値の1.2倍以内 | 失敗試行と出力長を分解する |
| 状態不明・重複 | いずれも0件 | 再開せず、台帳照合を継続 |
想定例では、1,000件の論理要求に対して1,080回APIを呼び出した場合、増幅率は1,080÷1,000=1.08です。うち40件を再試行し38件が期限内に成功すれば再試行後成功率は38÷40×100=95%となります。この二値を一緒に見れば、再送量を増やして表面上の成功だけを稼いでいないか判断できます。評価票は障害前28日、障害中、復旧後60分の三期間で比較します。
ステージングで障害を注入して確認する
本番前テストでは、成功応答を多数流すより、成否が曖昧になる境界を再現します。モックサーバーまたはAPIゲートウェイで状態コード、応答遅延、途中切断を注入し、実際のキューと台帳を通します。APIキーはステージング専用Projectのサーバー側シークレットとして保管し、ブラウザーやテスト結果へ出力しません。負荷試験の利用額上限も本番とは分離します。
| 注入する障害 | 期待する制御 | 確認する記録 |
|---|---|---|
| 要求数429とresetヘッダー | 指定時刻まで送信を待つ | 待機理由、次回時刻、キュー長 |
| トークン量429 | 長文ジョブを分離し流量を下げる | 入力トークン、残量、モデル |
| 401・失効キー | 再送せず資格情報を停止 | Project、キー識別子、交換履歴 |
| 500・503を連続25件 | 回路を開き試験要求だけ許可 | 失敗窓、遮断時刻、通知先 |
| 処理完了後に接続切断 | 状態不明へ隔離し副作用を止める | 冪等性キー、結果ID、照会結果 |
| キュー容量90% | 低優先度受付を制限 | 業務期限、破棄0件、退避先 |
合格条件は、最大試行数を超える要求0件、成功済み副作用の再実行0件、APIキーのログ出力0件、停止通知が5分以内、復旧後の試験要求が順序どおり記録されることです。タイムアウト値の直前と直後も各10回試し、偶然の一回成功で済ませません。不合格なら設定値を上げて回避せず、台帳更新と停止処理の順序を修正して同じケースを再実行します。
同期処理と非同期処理で回復方針を変える
対話画面の同期処理は、利用者が待てる時間を超えて再送を重ねないことが重要です。サーバー側の総時間を15秒とする想定なら、初回10秒、再試行1回5秒など、待機を含めた予算を先に配分します。時間切れでは受付IDを返して非同期へ切り替えるか、未完了として終了します。ブラウザーからAPIを直接呼ばず、認証済みの自社バックエンドがProject用資格情報を使います。
夜間集計や文書の一括処理は、待ち行列で時間をずらせるため、同時実行を下げて回復を待てます。ただし、業務期限、キューの最大保持期間、再投入責任者をジョブごとに持たせます。期限を過ぎた要求は成功するまで無限に残さず、デッドレターへ移して依頼元へ返します。新しいモデルへ自動で切り替える設計は、出力品質や価格が変わるため、事前評価済みの代替モデルだけに限定します。
画像生成、長い推論、大量ファイルを伴う要求は、通常の短文要求と同じレート枠やキューに混ぜると遅延原因を見失います。処理種別ごとに同時実行、最大出力、費用上限を分けます。即時性が必須で代替手段がなく、失敗時に人が介入できない業務は、この再試行方式だけでは運用できません。機能縮退画面、手作業への切替、受付停止のどれを採るかをサービス責任者が事前に決めます。
障害記録から設定を見直すタイミング
再試行設定は一度決めて終わりではありません。レート上限、利用モデル、API処理時間、入力長、ワーカー数が変われば、同じ待機値でも挙動が変わります。モデルまたはProjectの変更時、1要求当たり費用が二日連続で基準超過、再試行増幅率が週内に三回1.10超過、状態不明が一件でも発生、業務期限超過が月内に二件発生した場合を見直し開始条件とします。
障害記録には、開始・検知・停止・復旧・再開の各時刻、影響した要求数、最初のエラー、再試行回数、利用額、顧客影響、採った回避策を記載します。OpenAI側のrequest IDと自社トレースIDを対にし、資格情報や入力本文は必要最小限だけ別の保護領域へ保存します。設定変更の承認者、変更前後の値、適用したワーカー群も残し、翌日のレビューで原因と対策を分けて確認します。
恒久対策へ進む条件は、障害の再現手順があり、対策前に失敗し対策後に合格することです。原因が特定できないまま最大試行数やタイムアウトだけを増やす変更は行いません。障害が外部要因でも、キューがあふれた、通知が遅れた、状態照会ができなかった部分は自社側の改善対象です。変更後7日間は評価票を日次で確認し、基準外なら元の設定へ戻します。
停止から安全に再開する手順
復旧操作では、APIが応答し始めた直後に全キューを放流しないことが肝心です。まず新規送信を止めたまま、処理中と状態不明の要求を確定します。次に資格情報、Project、モデル、レート残量を確認し、既知の正常設定へ戻します。設定ファイルは版管理し、実行中ワーカーがどの版を読んだか追跡できるようにします。
- 隔離: 自動再試行を無効化し、対象キューを一時停止します。成功済み、失敗、状態不明を台帳で分けます。
- 保全: request ID、クライアント要求ID、エラー、試行時刻、トークン、結果IDを保存します。APIキーそのものは記録しません。
- 切り戻し: 直前に変えたワーカー数、タイムアウト、モデル、プロンプトを既知の正常版へ戻し、変更者と時刻を記録します。
- 小規模確認: 副作用のない5件を逐次送信し、成功、遅延、費用、重複の合格線を確認します。
- 段階再開: 同時実行を25%、50%、100%と15分ごとに上げ、各段階で評価票を再計算します。
- 残件処理: 業務期限順にキューを戻し、状態不明は担当者の照合後だけ再送します。
再開中に500系が直近20件中5件、429が2分継続、重複が1件、または費用見込みが日次上限を超えたら直ちに前段階へ戻します。二回目の停止では自動再開を禁止し、基盤運用と業務責任者の共同承認を必要とします。完全復旧はキュー残件0だけでなく、期限超過の説明、状態不明0、顧客連絡の完了まで含めて確定します。
次に取る行動:一つのAPI経路で再試行予算を測る
着手時は、本番の全経路を一度に変更せず、ステージングの副作用がない要約APIを一つ選びます。論理要求ID、試行番号、HTTP状態、request ID、残量ヘッダー、入力・出力トークン、総所要時間を同じトレースへ記録します。そのうえで429、503、処理完了後の接続切断を注入し、最大試行、回路遮断、状態不明の隔離が判定表どおり動くか確認します。
合格後は、平常負荷の25%で30分、50%で30分の順に試し、増幅率1.10以下、重複0件、資格情報の露出0件を満たした記録へ開発・基盤・業務の三者が署名します。一項目でも外れた場合は本番へ進めず、旧設定へ戻して不合格ケースを修正します。本番導入日には停止権限を持つ担当者を配置し、初回1時間の指標を15分ごとに確認してください。
参考文献・出典
- OpenAI公式ドキュメント「Rate limits」(版表記・更新日表記なし、2026年7月31日参照)。生成AI APIのレート制限ヘッダー、指数バックオフ、失敗要求の扱いに使用。
- OpenAI公式ドキュメント「Error codes」(版表記・更新日表記なし、2026年7月31日参照)。429・401・5xxの原因分類と、再試行・エラー処理の判断に使用。
- OpenAI公式ドキュメント「API Overview」(REST API v1、
openai-version: 2020-10-01、ページ更新日表記なし、2026-07-30参照) - OpenAI公式ドキュメント「Production best practices」(版表記・更新日表記なし、2026-07-30参照)