• Home
  • Popular
  • Login
  • Signup
  • Cookie
  • Terms of Service
  • Privacy Policy
avatar

Posted by User Bot


27 Feb, 2025

Updated at 21 Mar, 2025

Apache http client 5 timeout is not working - version httpclient5:5.4.1

I want to configure a timeout of 3 seconds against https://httpbin.org/delay/5 which respond back after 5 second only. This is to make sure a service which takes more than three second is doing a timeout after three seconds. I have followed the documentation and written below code where the httpclient is not timed out after 3 seconds instead it takes between 5 to 6 seconds to timeout.

public class HttpClientTimeoutExamplePoolingHttpClientConnectionManagerBuilder {
public static void main(String[] args) {
    try {

        DefaultClientTlsStrategy tlsStrategy = new DefaultClientTlsStrategy(SSLContext.getDefault());


        final PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
                .setTlsSocketStrategy(tlsStrategy)
                .setDefaultSocketConfig(SocketConfig.custom()
                        .setSoTimeout(Timeout.of(3, TimeUnit.SECONDS))
                        .build())
                .setMaxConnPerRoute(20)
                .setMaxConnTotal(200)
                .build();

        final RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(Timeout.of(1, TimeUnit.SECONDS))
                .setConnectTimeout(Timeout.of(3, TimeUnit.SECONDS))
                .setResponseTimeout(Timeout.of(3, TimeUnit.SECONDS))
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .evictExpiredConnections()
                .build();

        // Create GET request
        final HttpGet httpGet = new HttpGet("https://httpbin.org/delay/5");
        httpGet.setConfig(requestConfig);

        // Log start time
        long startTime = System.currentTimeMillis();
        System.out.println("Executing GET request at: " + startTime);

        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            try {
                long endTime = System.currentTimeMillis();
                System.out.println("Response received after: " + (endTime - startTime) + "ms");
                System.out.println("Response status: " + response.getCode());
                System.out.println("Response body: " + EntityUtils.toString(response.getEntity()));
            } finally {
                response.close();
            }
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            System.out.println("Exception after: " + (endTime - startTime) + "ms");
            System.out.println("Exception type: " + e.getClass().getName());
            System.out.println("Exception message: " + e.getMessage());
            e.printStackTrace();
        } finally {
            httpClient.close();
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Output:

app.verify.http.HttpClientTimeoutExamplePoolingHttpClientConnectionManagerBuilder.main()

Executing GET request at: 1740675604245

Exception after: 6575ms

Exception type: java.net.SocketTimeoutException

Exception message: Read timed out

I have tried different config (socket level, connection level, request level) but was not able achieve the timeout functionality.

Then I have changed the code to use PoolingHttpClientConnectionManager and Registry and everything started working

public class HttpClientTimeoutExamplePoolingHttpClientConnectionManager {

public static void main(String[] args) {
    try {

        Registry registry = RegistryBuilder.create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
        connectionManager.setDefaultSocketConfig(org.apache.hc.core5.http.io.SocketConfig.custom()
                .setSoTimeout(Timeout.of(3, TimeUnit.SECONDS))
                .build());
        connectionManager.setMaxTotal(200);
        connectionManager.setDefaultMaxPerRoute(20);

        // Define request config with timeouts
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(Timeout.of(1, TimeUnit.SECONDS))
                .setResponseTimeout(Timeout.of(3, TimeUnit.SECONDS))
                .setConnectionRequestTimeout(Timeout.of(3, TimeUnit.SECONDS))
                .build();

        // Build the client with timeouts applied at connection manager level
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .evictExpiredConnections()
                .build();

        // Create GET request
        final HttpGet httpGet = new HttpGet("https://httpbin.org/delay/5");
        httpGet.setConfig(requestConfig);

        // Log start time
        long startTime = System.currentTimeMillis();
        System.out.println("Executing GET request at: " + startTime);

        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            try {
                long endTime = System.currentTimeMillis();
                System.out.println("Response received after: " + (endTime - startTime) + "ms");
                System.out.println("Response status: " + response.getCode());
                System.out.println("Response body: " + EntityUtils.toString(response.getEntity()));
            } finally {
                response.close();
            }
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            System.out.println("Exception after: " + (endTime - startTime) + "ms");
            System.out.println("Exception type: " + e.getClass().getName());
            System.out.println("Exception message: " + e.getMessage());
            e.printStackTrace();
        } finally {
            httpClient.close();
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Output: app.verify.http.HttpClientTimeoutExamplePoolingHttpClientConnectionManager.main()

Executing GET request at: 1740675734246

java.net.SocketTimeoutException: Read timed out

Exception after: 3540ms

Exception type: java.net.SocketTimeoutException

Exception message: Read timed out

The issue is ConnectionSocketFactory, PlainConnectionSocketFactory and SSLConnectionSocketFactory are deprecated, so any idea how to achive timeout using non deprecated class?

I have tried https://github.com/apache/httpcomponents-client/blob/5.4.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java code and invoked the same URL with 3 second timeout and the behavior is same where request is taking around 5 to 6 second to timeout when I have configured the timeout as 3 seconds,.

Thanks