Spring RestTemplate — why the set timeout does not work

Jiří Čížek
3 min readJan 30, 2022

--

Have you set timeouts for the restTemplate and your requests are still living much longer than they should? Well, there are more timeouts than you think (sometimes). The “sometimes” here is the tricky part of the problem.

Let's create a simple example to demonstrate the problem.

Spring Boot 2.6.2 is used in the example

Consider a simple application whose purpose is to call one endpoint several times and record the duration of requests.

Of course, you have also configured the restTemplate available timeouts.

Use one of your favourite rest mocking tools (e.g. Mockoon) to mock the URL that we will call (localhost:8123). Set response to OK and also set the response delay to 5sec.

Now run it — you should get the correct output, which is the timeout of all requests in the set time period.

I/O error on GET request for "http://localhost:8123": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
I/O error on GET request for "http://localhost:8123": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
Request duration in Ms: 2030
Request duration in Ms: 2030

And now comes the tricky part.
Just add apache httpclient as a dependency.

implementation("org.apache.httpcomponents", "httpclient")

And run it again. This time some of the requests exceed the timeout easily.

Request duration in Ms: 2042
I/O error on GET request for "http://localhost:8123": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
Request duration in Ms: 2043
I/O error on GET request for "http://localhost:8123": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
I/O error on GET request for "http://localhost:8123": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
I/O error on GET request for "http://localhost:8123": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
Request duration in Ms: 4045
Request duration in Ms: 4046

How is it possible

Well, it is a part of “spring boot magic”. RestTemplate uses ClientHttpRequestFactory to create the request. To create this factory, the ClientHttpRequestFactorySupplier class is used, which scans the classpath when creating the factory, and if httpClient is found among the dependencies, the HttpComponentsClientHttpRequestFactory is created instead of the SimpleClientHttpRequestFactory that is used by default. As a consequence, the httpClient, provided by the dependency we are added, is used. This client uses a PoolingHttpClientConnectionManager and this is why our requests can live longer than the set timeouts.

Let’s say the pool size is 5. We create 6 requests — 5 requests start executing, but the 6th request is waiting to get a connection from the pool. Only when the first of the 5 requests reaches the timeout, the 6th request gets a connection and starts executing. This can lead to large delays when there are a large number of requests. Ther is a 3rd timeout to set “the timeout how long we are willing to wait to get the connection from the pool” The problem is the default value is “infinite” and there is no way to set it via restTemplateBuilder.

request execution timeline

Solution

There are multiple solutions to deal with this. One is to create a RequestFactory ourselves and set up what we want. In the RequestConfig we are able to set all the 3 timeouts.

Hope this was helpful and saved you some time ;)

--

--

Jiří Čížek

Software engineer/architect a DevOps enthusiast, dedicated to crafting quality architectures and maintainable clean, pragmatic code