【要約】「HTTP リトライしたら 3 回 POST されていた」タイムアウト ≠ 未到達という罠 [Zenn_Python] | Summary by TechDistill
> Source: Zenn_Python
Execute Primary Source
// Problem
開発者がRaspberry Pi上のbotにおいて、POSTリクエストが3回実行される問題に直面した。原因は、HTTPクライアントのタイムアウトとリトライ設定の不適切な組み合わせである。
- ・
timeout=5設定に対し、サーバーの応答が遅延した。 - ・
urllib3のRetry設定でPOSTをリトライ対象に含めていた。 - ・サーバー側が
Idempotency-Keyによる冪等性を保証していなかった。 - ・ReadTimeout発生時に、クライアントが同一リクエストを再送し、サーバー側で別リクエストとして受理された。
// Approach
重複実行を防ぐため、サーバーの仕様に応じた2つの解決策を提示している。
- リトライ時も同じキーを再利用し、サーバー側で重複を排除させる。
- ペイロードに
- 未作成の場合のみ再送を行うことで、擬似的に冪等性を確保する。
- ・**サーバーが冪等性に対応している場合**
Idempotency-Key ヘッダに一意のUUIDを付与する。- リトライ時も同じキーを再利用し、サーバー側で重複を排除させる。
- ・**サーバーが非対応の場合**
- ペイロードに
client_ref を含め、タイムアウト時はまずその識別子で状態を確認する。- 未作成の場合のみ再送を行うことで、擬似的に冪等性を確保する。
// Result
設計者が通信の不確実性を理解することで、副作用を伴うリクエストの「at-most-once」実行を保証できる。
- ・決済や外部投稿などの致命的な二重処理リスクを低減できる。
- ・
Idempotency-Keyの活用により、通信の不安定さを吸収しつつ整合性を保てる。 - ・状態確認APIの併用により、サーバー側の仕様に依存しない擬似的な冪等性が実現できる。
Senior Engineer Insight
> 「タイムアウト=未到達」という誤解は、分散システムにおける致命的な設計ミスに直結する。大規模なトラフィックを扱う現場では、ネットワークの不確実性は前提である。単にリトライ回数を増やすのではなく、通信の冪等性を設計の根幹に据えるべきだ。特に、副作用を伴うPOSTリクエストにおいて、
allowed_methods に POST を含める行為は極めて危険である。サーバーの仕様が不完全でも、クライアント側で状態確認を行う等の防衛策が必要だ。