Generic Top

The early-bird price of the new Learn Spring Security OAuth course packages will increase by $50 on Wednesday:

>> CHECK OUT THE COURSE

1. Overview

In this quick tutorial, we'll focus on different types of timeouts we can set for the OkHttp client.

For the more general overview of the OkHttp library, check our introductory OkHttp guide.

2. Connect Timeout

A connect timeout defines a time period in which our client should establish a connection with a target host.

By default, for the OkHttpClient, this timeout is set to 10 seconds.

However, we can easily change its value using the OkHttpClient.Builder#connectTimeout method. A value of zero means no timeout at all.

Let's now see how to build and use an OkHttpClient with a custom connection timeout:

@Test
public void whenConnectTimeoutExceeded_thenSocketTimeoutException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .connectTimeout(10, TimeUnit.MILLISECONDS)
      .build();

    Request request = new Request.Builder()
      .url("http://203.0.113.1") // non routable address
      .build();

    Throwable thrown = catchThrowable(() -> client.newCall(request).execute());

    assertThat(thrown).isInstanceOf(SocketTimeoutException.class);
}

The above example shows that the client throws a SocketTimeoutException when the connection attempt exceeds the configured timeout.

3. Read Timeout

A read timeout is applied from the moment the connection between a client and a target host has been successfully established.

It defines a maximum time of inactivity between two data packets when waiting for the server's response.

The default timeout of 10 seconds can be changed using OkHttpClient.Builder#readTimeout. Analogously as for the connect timeout, a zero value indicates no timeout.

Let's now see how to configure a custom read timeout in practice:

@Test
public void whenReadTimeoutExceeded_thenSocketTimeoutException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .readTimeout(10, TimeUnit.MILLISECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://httpbin.org/delay/2") // 2-second response time
      .build();

    Throwable thrown = catchThrowable(() -> client.newCall(request).execute());

    assertThat(thrown).isInstanceOf(SocketTimeoutException.class);
}

As we can see, the server doesn't return the response within the defined timeout of 500 ms. As a result, the OkHttpClient throws a SocketTimeoutException.

4. Write Timeout

A write timeout defines a maximum time of inactivity between two data packets when sending the request to the server.

Similarly, as for the connect and read timeouts, we can override the default value of 10 seconds using OkHttpClient.Builder#writeTimeout. As a convention, a zero value means no timeout at all.

In the following example, we set a very short write timeout of 10 ms and post a 1 MB content to the server:

@Test
public void whenWriteTimeoutExceeded_thenSocketTimeoutException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .writeTimeout(10, TimeUnit.MILLISECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://httpbin.org/delay/2")
      .post(RequestBody.create(MediaType.parse("text/plain"), create1MBString()))
      .build();

    Throwable thrown = catchThrowable(() -> client.newCall(request).execute());

    assertThat(thrown).isInstanceOf(SocketTimeoutException.class);
}

As we see, due to the large payload, our client isn't able to send a request body to the server within the defined timeout. Consequently, the OkHttpClient throws a SocketTimeoutException.

5. Call Timeout

A call timeout is a bit different than the connect, read and write timeouts we already discussed.

It defines a time limit for a complete HTTP call. This includes resolving DNS, connecting, writing the request body, server processing, as well as reading the response body.

Unlike other timeouts, it's default value is set to zero which implies no timeout. But of course, we can configure a custom value using OkHttpClient.Builder#callTimeout method.

Let's see a practical usage example:

@Test
public void whenCallTimeoutExceeded_thenInterruptedIOException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .callTimeout(1, TimeUnit.SECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://httpbin.org/delay/2")
      .build();

    Throwable thrown = catchThrowable(() -> client.newCall(request).execute());

    assertThat(thrown).isInstanceOf(InterruptedIOException.class);
}

As we can see, the call timeout is exceeded and the OkHttpClient throws an InterruptedIOException.

6. Per-Request Timeout

It's recommended to create a single OkHttpClient instance and reuse it for all the HTTP calls across our application.

Sometimes, however, we know that a certain request takes more time than all the others. In this situation, we need to extend a given timeout only for that particular call.

In such cases, we can use an OkHttpClient#newBuilder method. This builds a new client that shares the same settings. We can then use the builder methods to adjust timeout settings as needed.

Let's now see how to do this in practice:

@Test
public void whenPerRequestTimeoutExtended_thenResponseSuccess() throws IOException {
    OkHttpClient defaultClient = new OkHttpClient.Builder()
      .readTimeout(1, TimeUnit.SECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://httpbin.org/delay/2")
      .build();

    Throwable thrown = catchThrowable(() -> defaultClient.newCall(request).execute());

    assertThat(thrown).isInstanceOf(InterruptedIOException.class);

    OkHttpClient extendedTimeoutClient = defaultClient.newBuilder()
      .readTimeout(5, TimeUnit.SECONDS)
      .build();

    Response response = extendedTimeoutClient.newCall(request).execute();
    assertThat(response.code()).isEqualTo(200);
}

As we see the defaultClient failed to complete the HTTP call because of the exceeded read timeout.

That's why we created the extendedTimeoutClient, adjusted the timeout value, and successfully executed the request.

7. Summary

In this article, we explored different timeouts we can configure for the OkHttpClient.

We also shortly described when the connect, read and write timeouts are applied during an HTTP call.

Additionally, we showed how easy it is to change a certain timeout value only for a single request.

As usual, all the code examples are available over on GitHub.

Generic bottom

The early-bird price of the new Learn Spring Security OAuth course packages will increase by $50 on Wednesday:

>> CHECK OUT THE COURSE

Leave a Reply

avatar
  Subscribe  
Notify of