3

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

  1. How can I find a place where this time is outset? those parameters don't work for me

                 .setSocketTimeout(25_000)
                 .setConnectTimeout(26_000)
    
  2. What is the best way to fix this problem? (I mean retry request or change timeout or reconnect after or before each request)

1
  • You probably need to configure your connection pool to test connections Commented Nov 30, 2021 at 20:51

1 Answer 1

7

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:

  1. Validate persistent connections upon lease from the connection pool after a certain period of inactivity (for example, after 1s)
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    cm.setValidateAfterInactivity(1000);
    CloseableHttpClient httpclient = HttpClients.custom()
            .setConnectionManager(cm)
            .build();
  1. Proactively evict expired connections and those that have been idle over a certain period of time (for example, 5s) from the connection pool
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    cm.setValidateAfterInactivity(1000);
    CloseableHttpClient httpclient = HttpClients.custom()
            .setConnectionManager(cm)
            .evictExpiredConnections()
            .evictIdleConnections(5L, TimeUnit.SECONDS)
            .build();
  1. If everything else fails, retry requests that are safe to retry. One might want to use a custom 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();
  1. Evict connections from the pool manually when expecting a long period inactivity. This is what HttpClient does for you automatically when configured with evictIdleConnections method at the cost of an extra monitor thread.
    cm.closeIdleConnections(0, TimeUnit.MICROSECONDS);
Sign up to request clarification or add additional context in comments.

3 Comments

can you describe, how does it work? I mean, I use a connection pool/ I close response after each request. Why httpClient holds a connection after closing?
It is called connection persistence. Please see datatracker.ietf.org/doc/html/rfc7230#section-6.3
Thank you! but I still do not understand what is the meaning of closing response.close()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.