-
Notifications
You must be signed in to change notification settings - Fork 9
Request Timeout
Herokuのルーティングメッシュはレスポンスを返すまでに30秒以上かかるリクエストを発見して強制終了します。カスタマイズ可能なエラーページがクライアントに返却され、H12エラーがアプリケーションログに出力されます。
Webのリクエストは通常500ミリ秒以下で処理されます。200ミリ秒以下なら理想的です。なので30秒以上かかるリクエストはベストプラクティスとされるレスポンスよりも遥かに遅いものです。
##ロングポーリングとストリーミングレスポンス
CedarスタックはロングポーリングとストリーミングレスポンスといったHTTP 1.1の機能をサポートしています。アプリケーションはクライアントに最初の1バイトを返すために30秒の制限時間を持っています。しかし、その後に送出されるバイト(クライアントが受け取るにせよ、アプリケーションが送出するにしろ)は55秒間の時間制限をリセットします。もし55秒の間にデータが全く送出されなければ、その接続は強制的に切断されます。
##タイムアウトの挙動
エラーページがクライアントに表示され、接続が切れても、タイムアウトが起きる時はそのWebプロセスがリクエストを処理するために残り続けます。後続のリクエストはレスポンスを返せない同一のプロセスにルーティングされる可能性があるため、さらなる問題の原因になります。(アプリケーションの開発言語やフレームワークの並列処理に依存します)
もし不安があれば、Rubyのrack-timeoutのようなツールを使って、30秒以上プロセスが続かないように保証しましょう。
##リクエストタイムアウトのデバッグ
リクエストタイムアウトの一因はコードの無限ループです。ローカル環境でテストし(場合によってはpgbackupsを使って本番環境のデータをコピーして)、問題が再現するかどうか確認し、バグを修正してください。
また、Webプロセスで以下のような時間のかかる処理を行っている可能性もあります。
- メール送信
- リモートAPIへのアクセス(Twitterへの投稿、Flickrへの問い合わせ等)
- Webスクレイピング / クローリング
- 画像やPDFのレンダリング
- 重たい計算 (フィボナッチ数列の計算等)
- 重たいデータベース処理 (重くて膨大な数のクエリ、N+1クエリ等)
もしそうであれば、そうした重たい処理はWebリクエストからバックグラウンドの非同期処理に移動させてください。
別の種類のタイムアウトはアプリケーションが使用する外部サービスが使用不能であったり、過負荷であるときに発生します。この場合、そうした処理をバックグラウンドに移動させない限り、ほぼ確実にタイムアウトします。そうしたリクエストをどうしてもWebリクエスト中に処理しなければいけない場合は、処理に失敗する場合を考慮に入れてください。例えば、ほとんどの言語ではHTTPリクエスト中のタイムアウトを特定することができます。