I created an Apache HTTP client
CloseableHttpClient client = HttpClients.custom()
.setMaxConnPerRoute(25)
.setMaxConnTotal(50)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectionRequestTimeout(20_000)
.build())
.build();
I am using it as a singleton. I have this method for sending requests:
public RestResponse sendPost(String serverUrl, String body) throws RestException {
try {
HttpPost httpPost = new HttpPost(serverUrl);
httpPost.setEntity(new StringEntity(body));
try (CloseableHttpResponse response = client.execute(httpPost)) {
RestResponse restResponse = new RestResponse();
restResponse.setCode(response.getStatusLine().getStatusCode());
restResponse.setBody(EntityUtils.toString(response.getEntity()));
return restResponse;
}
} catch (Exception e) {
throw new RestException(e);
}
}
It works fine. But after some time (5-6 min) of idle, if I send a request I get "java.net.SocketException: Connection reset"
I have 2 questions
How can I find a place where this time is outset? those parameters don't work for me
.setSocketTimeout(25_000)
.setConnectTimeout(26_000)
What is the best way to fix this problem? (I mean retry request or change timeout or reconnect after or before each request)
This is a general limitation of the classic (blocking) i/o: blocking connections cannot react to any i/o events when idle (not engaged in an i/o operations). Likewise, timeout settings have no effect on idle connections.
There are several defensive measures one can employ to minimize the chances of a persistent connection reset:
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.evictExpiredConnections()
.evictIdleConnections(5L, TimeUnit.SECONDS)
.build();
HttpRequestRetryHandler
implementation instead of the default one when more control is necessary. PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE)
.build();
evictIdleConnections
method at the cost of an extra monitor thread. cm.closeIdleConnections(0, TimeUnit.MICROSECONDS);