1. Overview

In this tutorial, we'll look at how we can configure the timeout values for Apache HttpClient 4.

By configuring the timeout values, we can increase the responsiveness of our application and improve the usage of system resources.

2. Different Timeout Values

Let's first start with the different timeout values HttpClient provides.

Firstly, we have the connection request timeout which defines how long a client should wait for a connection from the connection pool. For example, if all connections are busy executing an HTTP request, subsequent connection requests will wait until a connection becomes available.

Secondly, we have the timeout for connecting a server. This value defines how long the HttpClient should wait when trying to connect a server.

Lastly, we have the socket timeout which defines the maximum interval between consequent network packets.

3. Configuring Timeout

Now that we know different timeout types, we'll see next how to configure these values.

3.1. Configuring Timeout Globally using RequestConfig

We'll first configure the timeout values globally using the RequestConfig class:

public void executeAndSetTimeoutWithRequestConfig() throws Exception {
    RequestConfig requestConfig = RequestConfig.custom()
      .setConnectionRequestTimeout(1000)
      .setConnectTimeout(1000)
      .setSocketTimeout(1000)
      .build();
    try (CloseableHttpClient httpClient = HttpClients.custom()
      .setDefaultRequestConfig(requestConfig)
      .build()) {
        final HttpGet httpGet = new HttpGet(GET_URL);
        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            EntityUtils.consumeQuietly(response.getEntity());
        }
    }
}

Here, we're creating an instance of RequestConfig. Also, we're setting all timeout values as 1000 ms. Then, we're providing this instance to HttpClient - HttpClients.custom().setDefaultRequestConfig().

Note that HttpClient will use this timeout configuration for all HTTP requests.

3.2. Configuring Timeout per Request using RequestConfig

Next, let's see how we can set the timeout values per request.

Similar to the previous example, we'll use the RequestConfig class:

public void executeAndSetTimeoutWithRequestConfigPerRequest() throws Exception {
    try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
        final RequestConfig requestConfig = RequestConfig.custom()
          .setConnectionRequestTimeout(1000)
          .setConnectTimeout(1000)
          .setSocketTimeout(1000)
          .build();
        final HttpGet httpGet = new HttpGet(GET_URL);
        httpGet.setConfig(requestConfig);
        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            EntityUtils.consumeQuietly(response.getEntity());
        }
    }
}

Here, we're again creating an instance of RequestConfig. However, instead of setting it to HttpClient, we're setting this configuration to a single HTTP request - using httpGet.setConfig().

3.3. Configuring Timeout Globally using HttpRequestFutureTask

Lastly, we'll now use HttpRequestFutureTask to define a timeout value.

Unlike the others, in this approach, we won't configure the different timeout values. Instead, we'll put a single timeout for the whole HTTP request execution:

public void executeAndSetTimeoutWithFutureTask() throws Exception {
    HttpClient httpclient = HttpClientBuilder.create()
      .setMaxConnPerRoute(5)
      .setMaxConnTotal(5)
      .build();
    ExecutorService execService = Executors.newFixedThreadPool(5);
    FutureRequestExecutionService requestExecutionService = new FutureRequestExecutionService(httpclient, execService);
    try {
        HttpGet httpGet = new HttpGet(GET_URL);
        ResponseHandler<Boolean> handler = response -> response.getStatusLine().getStatusCode() == 200;
        HttpRequestFutureTask<Boolean> futureTask = requestExecutionService.execute(httpGet, HttpClientContext.create(), handler);
        Boolean isOk = futureTask.get(1, TimeUnit.SECONDS);
        System.out.println("Is OK? : " + isOk);
    } finally {
        requestExecutionService.close();
    }
}

Here, we're creating an instance of FutureRequestExecutionService and submitting our HTTP requests to this instance. As a result, we're getting HttpRequestFutureTask. After this step, we can block on this Future and specify a timeout value. In our case, we're waiting for up to 1 second.

4. Summary

In this tutorial, we've looked at how we can configure timeout values for Apache HttpClient using different approaches.

As always, the source code for all examples is available on Github.