API Timeoutの診断と対策:安全に再試行するか判断する方法
LLM API timeoutの発生層を特定し、該当する制限だけを変更して、二つの対照テストで復旧を確認する実践ガイド。
目次
API Timeoutの診断と対策:安全に再試行するか判断する方法
API Timeout は、リクエスト経路のどこかが待機を打ち切ったことを示します。クライアントが接続できなかった、プロキシがアイドル状態のstreamを閉じた、アプリケーション全体のdeadlineが切れた、またはgatewayがupstreamモデルから時間内に応答を得られなかった可能性があります。この表示だけではモデル停止とは判断できません。
再試行する前に、例外クラス、取得できたHTTP statusとbody、経過時間、request ID、受信済みchunkの有無を記録します。その証拠から確認できた層の制限だけを変更してください。すべてのtimeoutを一度に延長すると原因が隠れ、結果不明の操作を重複実行する恐れがあります。
BetterToken経由のリクエストなら、retry前にDashboardを開き、時刻、モデル、status、Token使用量を照合してください。APIに到達したリクエストとgateway以前の失敗をすぐに分けられます。
一つのtimeoutに複数の原因がある理由
アプリケーション / SDK
→ DNSとTCP/TLS
→ 社内proxyまたはreverse proxy
→ API gateway
→ upstreamモデル
→ クライアントへのstreaming応答
Connect timeout はDNS、TCP、TLSの接続確立に関係します。Readまたはstream-idle timeout は、クライアントの制限時間内に次のchunkが届かなかった状態です。Pool timeout は空き接続を待つクライアント側の制限です。全体deadline は業務処理全体を制限し、upstream timeout はgatewayやproviderが持つ別の制限です。一つを変更しても他は延長されません。
切断した層を特定する
| 観測した信号 | 想定する層 | 次に確認すること |
|---|---|---|
httpx.ConnectTimeout、HTTP応答なし | DNS、TCP、TLS | 同じruntimeで再現し、DNS、CA、proxy、firewallを比較 |
chunk受信前または間でhttpx.ReadTimeout | client read/idleまたは中間proxy | first byteとchunk間隔を測定し、proxyのidle制限を確認 |
| HTTP statusとerror bodyあり | gatewayまたはupstream | status、body、request IDを保存し、providerのerror contractに従う |
httpx.PoolTimeout | client connection pool | concurrencyとpool使用率を測り、飽和を確認してから制限を変更 |
| 毎回同じ総時間でcancel | application、job runner、reverse proxy | deadlineの所有者を特定し、下位のtimerと比較 |
順序は、信号の保存、同じhostまたはcontainerでの再現、中間proxyの確認、gatewayとupstreamの確認です。モデル、prompt、network、endpoint、proxyは固定し、各テストで一つの変数だけを変更します。
HTTPXはconnect、read、write、poolのtimeoutを別々に定義しています。普遍的な秒数はありません。実際の値は、計測したrequest phase、chunk間の想定停止時間、全体deadlineから決めます。
timeout、出力量、retryを変更する条件
- DNS/TCP/TLSの遅延を確認した場合だけconnect timeoutを変更します。
- 接続後にchunk間で中間制限が切れると確認した場合だけreadまたはidle timeoutを変更します。
- 下位層が正常で、業務処理を長く許容できる場合だけ全体deadlineを延長します。
- 制御した長いテストだけが失敗する場合は出力を減らすか分割します。計測なしで原因と断定しません。
429やcontext overflowは別の信号です。connect timeoutと混同しません。
結果不明の操作を重複させない安全なretry
送信後のtimeoutは、まず結果不明として扱います。ローカルtask IDはログ照合に役立ちますが、サーバー上の二回目の処理を防ぎません。サーバーがidempotencyまたはstatus lookupを明示的に提供し、外部の証拠から最初のrequestが受理されていないと確認できる場合だけ自動retryします。
最低限のチェック項目:
- request ID、status/body、timestamp、受信済みchunkを保存する。
- 非idempotent操作を繰り返す前に実際の結果を確認する。
- 部分的に受信したstreamを自動再送しない。二回目のgenerationと追加利用が発生する可能性がある。
- 試行回数と全体deadlineを制限し、SDK、proxy、applicationのretryを合算する。
- response作成時だけでなく、SSE iteration中の例外も捕捉する。
二つのテストで復旧を確認する
- 短い対照リクエスト: 小さな応答を要求し、status、first byteまでの時間、総時間、request ID、stream完了を記録します。失敗したら、まずnetwork、authentication、endpointを確認します。
- 制御した長いリクエスト: 短いテストの成功後、期待する出力だけを増やすか元のworkloadに戻します。モデル、endpoint、network、proxyは変更しません。このテストだけ失敗する場合、read/idle timeout、全体deadline、中間制限を比較します。
短いテストと元のシナリオの一回の再実行が期待どおり完了し、説明できない重複がないときに復旧を確認できます。リクエストがBetterTokenに到達した場合は、Dashboardで時刻、モデル、status、Token使用量を照合し、その後にendpoint contractを確認してください。