このページに書いてあること。
Javaアプリの開発で、リクエストタイムアウトとレスポンスタイムアウトで処理が異なっていることを改めて知ったのでリマインダとしてメモ
- 発生した問題
- リクエストタイムアウト時の挙動
- レスポンスタイムアウト時の挙動
背景:
アプリを作っているときに、リクエストとレスポンスのタイムアウトを検知してリトライを行うコードがあったのですが、リクエストタイムアウトはうまくいくのにレスポンスタイムアウトは上手くいかない。
上手くいく・いかないの違いは、想定したタイムアウト時間を待つかどうか。
つまり、リクエストタイムアウトは設定したタイムアウト時間を待ってからSocketTimeOutExceptionをスローするのに対し、
レスポンスタイムアウトでは初回発生時こそタイムアウト時間を待つが、2回目以降は一切待たずに処理を継続してしまった。
問題のコードは以下のような感じ。
con.connect(); // レスポンスコード取得 con.getResponseCode();
非常に単純で、1行目で接続・2行目でデータの受信をしようとしている。
で、このコードをtry/catchで囲んであって、リクエスト・レスポンスタイムアウトが発生した場合hリトライ処理を行うようになっている。
発生した事象をおさらいすると、
1行目では常にタイムアウト分の秒数を待ってからタイムアウト
2行目では一度レスポンスタイムアウトが発生して以降は、再接続で同じ処理を通過してもタイムアウト分待たずにレスポンスタイムアウト扱い。
理由は、HttpUrlConnectionクラスの実装にありました。
connectでタイムアウトが発生した場合は何も情報を残さずに例外をスローしてくるので、次回接続時に新しく接続を試みます。
getResponseCodeでは接続自体は成功した後の処理ですが、ここで例外が発生するとrememberedExceptionというエリアに発生した例外が格納されます。
このエリアに値があると、タイムアウト分の時間を待たずに同じ例外を投げてくるというものです。
何この仕様。
回避するには、HttpUrlConnectionクラスを新しく作り直す必要があります。