Apache HttpClient の DefaultHttpRequestRetryHandler は ConnectTimeoutException のときはリトライしない

Apache HttpClient はデフォルトで3回リトライする機能を持っています。しかし、コネクションタイムアウト (ConnectTimeoutException) のときはリトライしません。すべてドキュメントに書いてあることなんですが、そのあたりを調べたときのメモ。

※以下は Apache HttpClient 4.4.1 で調べています。

HttpClientBuilder#setRetryHandler でハンドラを設定せずに HttpClient を生成すると、デフォルトで DefaultHttpRequestRetryHandler が使われます。

以下、HttpClientBuilder#build から抜粋。

if (!automaticRetriesDisabled) { // automaticRetriesDisabled は デフォルトで false
    HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
    if (retryHandlerCopy == null) {
        retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE; // INSTANCE は new DefaultHttpRequestRetryHandler() で初期化されている
    }
    execChain = new RetryExec(execChain, retryHandlerCopy);
}

以下、DefaultHttpRequestRetryHandler のドキュメントから抜粋。

DefaultHttpRequestRetryHandler (Apache HttpClient 4.4.1 API)

Create the request retry handler with a retry count of 3, requestSentRetryEnabled false and using the following list of non-retriable IOException classes: InterruptedIOException, UnknownHostException, ConnectException, SSLException

余談ですが、最初、ここの non-retriablenon-retrieval に読み間違えて、全然見当違いな解釈をしていたことは内緒です。で、デフォルトコンストラクタを呼び出すと、リトライ不可能な IOException として以下が設定されるようです。

  • InterruptedIOException
  • UnknownHostException
  • ConnectException
  • SSLException

以下、DefaultHttpRequestRetryHandler#retryRequest からリトライ処理を抜粋。

if (this.nonRetriableClasses.contains(exception.getClass())) {
    return false;
} else {
    for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
        if (rejectException.isInstance(exception)) {
            return false;
        }
    }
}

この this.nonRetriableClasses に上記4つのクラスが設定されています。ConnectTimeoutExceptionInterruptedIOException のサブクラスなので、retryRequestfalse を返すことになります。

したがって、ハンドラを設定していない HttpClient では、コネクションタイムアウトのときにリトライしません。

(参考) Chapter 1. Fundamentals

  • 1.5.3. Automatic exception recovery
  • 1.5.4. Request retry handler