This article is based on HttpClient 4.5.13
When requesting external services using HTTP, retries are often required due to network or service instability. Retry can certainly be achieved by hand-lifting code, but a better way is to achieve it through existing mechanisms. Two types of retries are supported in HttpClient:
- Retry the exception.
- Service unavailable retry.
Abnormal retry
HttpClient throws two types of exceptions:
java.io.IOException
ClientProtocolException
Java.io.IOException is considered nonfatal and recoverable, while ClientProtocolException is considered fatal and unrecoverable.
Note that ClientProtocolException is a subclass of java.io.IOException.
If this is how you create HttpClient
CloseableHttpClient httpClient = HttpClients.custom().build();
Copy the code
Exception retry is enabled by default. See the httpClientBuilder.build () method for the code below
// Add request retry executor, if not disabled
if(! automaticRetriesDisabled) { HttpRequestRetryHandler retryHandlerCopy =this.retryHandler;
if (retryHandlerCopy == null) {
retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
}
execChain = new RetryExec(execChain, retryHandlerCopy);
}
Copy the code
AutomaticRetriesDisabled isa Boolean variable that defaults to false, so the condition defaults to HttpRequestRetryHandler using a default if HttpRequestRetryHandler is not set.
DefaultHttpRequestRetryHandler mainly has three member variables
retryCount
Retry countrequestSentRetryEnabled
Whether the request can be retried after it was successfully sent, but not after the request was successfully sent.nonRetriableClasses
A collection of non-retry exception classes that will not be retried if the exception is one specified in the collection.
The default instance variable Settings are as follows
retryCount=3
To retry a maximum of three times.requestSentRetryEnabled=false
If the message is successfully sent, it will not retrynonRetriableClasses
It contains the following four types:InterruptedIOException
UnknownHostException
ConnectException
SSLException
Retry the execution of the logic in the org. Apache. HTTP. Impl. Execchain. RetryExec, interested can go to the next.
The default retry logic is as follows
@Override
public boolean retryRequest(final IOException exception, final int executionCount, final HttpContext context) {
Args.notNull(exception, "Exception parameter");
Args.notNull(context, "HTTP context");
if (executionCount > this.retryCount) {
// Do not retry if over max retry count
// The number of retries is exceeded
return false;
}
// Do not retry if the exception is ignored
if (this.nonRetriableClasses.contains(exception.getClass())) {
return false;
}
for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
if (rejectException.isInstance(exception)) {
return false; }}final HttpClientContext clientContext = HttpClientContext.adapt(context);
final HttpRequest request = clientContext.getRequest();
if(requestIsAborted(request)){
return false;
}
// Idempotent methods can be retried
if (handleAsIdempotent(request)) {
// Retry if the request is considered idempotent
return true;
}
// Try again if the request is not sent or if it is
if(! clientContext.isRequestSent() ||this.requestSentRetryEnabled) {
// Retry if the request has not been sent fully or
// if it's OK to retry methods that have been sent
return true;
}
// otherwise do not retry
return false;
}
Copy the code
Note that the lower idempotent methods are not post or PUT, so the judgment will not hold, but if requestSentRetryEnabled is set to True, retransmissions will still occur, and you need to ensure that the interface being called is idempotent when reprocessing POST and PUT requests.
Some people may experience problems, such as reporting an exception for SocketTimeoutException but not retrying it, because SocketTimeoutException is a subclass of InterruptedIOException and is ignored by default. If you need to retry, you can customize an HttpRequestRetryHandler and then set it up again.
HttpClients.custom().setRetryHandler(httpRequestRetryHandler).build();
Copy the code
Actually use inheritance DefaultHttpRequestRetryHandler, then extend some own implementation is very convenient.
It’s also easy to disable callback retries if you want
HttpClients.custom().disableAutomaticRetries().build();
Copy the code
Service unavailable retry
In some cases, the request was successful, but the HTTP status code may not be 2xx, in which case you need to retry. HttpClient provides a mechanism for retrying when a service is unavailable.
Retry logic of execution in the org. Apache. HTTP. Impl. Execchain. ServiceUnavailableRetryExec, interested can look at.
The HttpClient provides the default policy, but it is not enabled by default
DefaultServiceUnavailableRetryStrategy serviceUnavailableRetryStrategy = new DefaultServiceUnavailableRetryStrategy();
httpClient = HttpClients.custom().setServiceUnavailableRetryStrategy(serviceUnavailableRetryStrategy).build();
Copy the code
Retry logic
@Override
public boolean retryRequest(final HttpResponse response, final int executionCount, final HttpContext context) {
return executionCount <= maxRetries &&
response.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE;
}
Copy the code
When there is no more than retries and retry return code is 503, of course, can also custom ServiceUnavailableRetryStrategy to achieve your needs.
It is also possible to set the interval between retry requests.