Understanding Apache HttpClient's Default Retry Strategy and How to Disable It
This article examines the default retry mechanism of Apache HttpClient 4.5.5, explains how the RetryExec executor and DefaultHttpRequestRetryHandler work, details the conditions under which retries occur or are skipped, and shows how to disable automatic retries when building an HttpClient instance.
When interacting with third‑party services via HttpClient, the request status is critical, raising questions about the default retry policy, its principles, and how to turn it off. The article explores these issues by analyzing the HttpClient source code (version 4.5.5).
General Usage
HttpClient instances can be created either with HttpClients.custom().setXXX().build() for customized configurations (e.g., SSL certificates, proxy, connection pool) or with HttpClients.build() for a default client. Both methods ultimately produce a CloseableHttpClient that is an InternalHttpClient implementation.
Retry Execution (RetryExec)
The client builds an execution chain where RetryExec wraps the basic executor MainClientExec. During each request, a loop records the execution count and, on an IOException, consults the retry handler to decide whether to retry.
Default Retry Handler (DefaultHttpRequestRetryHandler)
The default handler is a singleton ( DefaultHttpRequestRetryHandler.INSTANCE) with the following policy:
Maximum of 3 retry attempts.
No retry if the request has already been successfully sent.
Do not retry on InterruptedIOException, UnknownHostException, ConnectException, or SSLException (and their subclasses).
Key constructor and method signatures:
public DefaultHttpRequestRetryHandler() { this(3, false); } public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { ... }Request Sent Flag
The context attribute http.request_sent tracks whether the request body has been flushed to the network. It is set to false before sending, changed to true after a successful flush(), and consulted by the retry handler to avoid retrying already‑sent requests.
HTTP Request Flow
The low‑level method HttpRequestExecutor.doSendRequest performs the following steps:
Initialize http.request_sent to false.
Write request headers and, if applicable, the request entity.
Flush the connection; on success set http.request_sent to true.
Receive the response.
If flush() throws an IOException (e.g., socket reset or close), the request is considered not sent and may be retried according to the handler policy.
Impact on Business Logic
For GET requests, up to three retries are possible because they are idempotent. For POST requests, retries occur only when the request body has not been successfully written and flushed. Time‑outs such as SocketTimeoutException inherit from InterruptedIOException and therefore do not trigger retries.
Disabling Retries
When building an HttpClient, calling disableAutomaticRetries() sets the internal flag automaticRetriesDisabled to true, preventing the builder from inserting RetryExec into the execution chain. Example:
HttpClient client = HttpClients.custom().disableAutomaticRetries().build();Conclusion
The default HttpClient retry mechanism retries only on I/O exceptions that are not in the excluded list, respects a maximum of three attempts, and avoids retrying already‑sent requests. Understanding this behavior allows developers to fine‑tune reliability or explicitly disable retries when necessary.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
