- How to set read time out for calling REST services using Spring REST template ?
- Setting the read time out locally:
- Setting the read time out at the application level:
- Configure Timeouts with Spring RestTemplate
- Spring RestTemplate Timeout
- Connection vs Read Timeout
- Configure RestTemplate timeout
- Test a Connect timeout
- Test a Read timeout
- Run the tests
- Conclusion
- Giau Ngo
How to set read time out for calling REST services using Spring REST template ?
Let’s say you are invoking a REST service using Spring’s REST template.
And you want to set the read time out to a certain value. You don’t want the invoked service to take too much time to send data.
You can do this in two ways:
Setting the read time out locally:
Let’s assume you are calling a GET service deployed at localhost:8080 which just returns a string message.
To invoke this using Spring REST template you can do this :
RestTemplate template = new RestTemplate(); String response = template.getForObject("http://localhost:8080/getData",String.class);
The variable response will have the value returned by the GET service.
If you want to wait only for half a second before the GET service returns data , you can set the read time out using SimpleClientRequestFactory like this:
RestTemplate template = new RestTemplate(); SimpleClientHttpRequestFactory rf = (SimpleClientHttpRequestFactory)template.getRequestFactory(); rf.setReadTimeout(500); String response = template.getForObject("http://localhost:8080/getData",String.class);
An instance of SimpleClientHttpRequestFactory is obtained from the rest template instance. And the time out value is set on it.
That’s it. Now if the GET service takes more than half a second to return data the service throws an exception like this :
java.net.SocketTimeoutException: Read timed out at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283) ~[na:na] at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309) ~[na:na] at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350) ~[na:na] at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803) ~[na:na] at java.base/java.net.Socket$SocketInputStream.read(Socket.java:982) ~[na:na]
Notice that read time out is different from connection time out . Connection time is the time taken to establish connection with the consumed REST service .Read time is the time taken to read the data returned by the REST service.
Setting the read time out at the application level:
If you want the above read time out configuration for all of the REST services consumed by the application you can add a configuration file and create a custom REST Template inside the file like this:
package com.resttemplate.demo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; @Configuration public class RestConfig < @Bean public RestTemplate myRestTemplate()< SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setReadTimeout(500); return new RestTemplate(requestFactory); >>
The above configuration creates a customized Spring Bean (RestTemplate bean).
To use this bean, autowire it in the class where you are consuming the third party REST service.
package com.resttemplate.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.client.RestTemplate; public class RestClient < @Autowired private RestTemplate restTemplate; public String getDataFromService() < String response = restTemplate.getForObject("http://localhost:8080/getData", String.class); return response; >>
If you invoke the service now and it again takes more than half a second to return data , the same read time out exception is thrown.
Connection time out can be set out the same way as read time out using setConnectTimeOut() method of SimpleClientRequestFactory class.
This design approach followed by Spring is less intuitive though. Why not add a method setReadTimeOut() on the class RestTemplate itself? Why does the developer need to know about SimpleClientRequestFactory? .
Configure Timeouts with Spring RestTemplate
In this Spring boot2 RestTemplate timeout example, learn to configure connection timeout and read timeout in Spring RestTemplate with example.
By default, RestTemplate uses SimpleClientHttpRequestFactory which depends on the default configuration of HttpURLConnection. Look inside the class source, and you will find this.
private int connectTimeout = -1; private int readTimeout = -1;
By default, RestTemplate uses the timeout property from JDK installed on the machine which is always infinite if not overridden. To override the default JVM timeout, we can pass these properties during the JVM start. The time unit is in milliseconds.
-Dsun.net.client.defaultConnectTimeout=5000 -Dsun.net.client.defaultReadTimeout=5000
2. Configure Timeout with SimpleClientHttpRequestFactory
To programmatically override the timeout properties, we can customize the SimpleClientHttpRequestFactory class as below.
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory()); //Override timeouts in request factory private SimpleClientHttpRequestFactory getClientHttpRequestFactory()
3. Using Apache HttpClient
The SimpleClientHttpRequestFactory helps in setting timeout but it is very limited in functionality and may not prove sufficient in real-time applications. In production code, we may want to use a feature-rich library such as Apache HttpClient.
The HTTPClient library provides other useful features such as a connection pool, idle connection management etc.
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory()); //Override timeouts in request factory private SimpleClientHttpRequestFactory getClientHttpRequestFactory()
It is very necessary to have timeout property while interacting with remote systems. Any performance issue they cause may hamper the user experience and can bring down the whole application.
In production code, always opt to use HttpClient library. You may consider using SimpleClientHttpRequestFactory only while writing the JUnit tests.
Drop me your questions related to spring boot resttemplate connection timeout example.
Spring RestTemplate Timeout
When configuring RestTemplate timeout, there’re two settings that need to be considered, Connection and Read timeout. They can be configured by using RestTemplateBuilder in Spring Boot applications or SimpleClientHttpRequestFactory in Spring applications
Apart from that, you can connect to a non-routable IP address or an existing host with a blocked port to test a RestTemplate Connect timeout. As MockRestServiceServer overwrites RestTemplate Request factory settings, to test Read timeout, you can simulate a delayed backend controller with Thread.sleep and write an integration test in Spring Boot with @SpringBootTest
Let’s walk through this tutorial to explore in more detail
Connection vs Read Timeout
Connection timeout is used when opening a communications link to the remote resource. A java.net.SocketTimeoutException is thrown if the timeout expires before the connection can be established
Read timeout is used when reading from Input Stream when a connection is established to a remote resource. A java.net.SocketTimeoutException is also thrown if the timeout expires before there is data available for reading
Configure RestTemplate timeout
In Spring Boot, the connection and read timeout can be configured via RestTemplateBuilder
static final int TIMEOUT = 500; @Bean RestTemplate restTemplateWithConnectReadTimeout()
If your project doesn’t use Spring Boot, you can configure them via SimpleClientHttpRequestFactory
static final int TIMEOUT = 500; @Bean RestTemplate restTemplateTimeoutConfigWithRequestFactory()
The default value of Connect and Read timeout is 0 specifies an infinite timeout
You can find the full configuration code as below
Test a Connect timeout
You can test a RestTemplate Connect timeout setting by requesting to a non-routable IP address such as 10.255.255.255 or to an existing host but with a blocked port such as http://example.com:81
Test a Read timeout
To test the RestTemplate Read timeout, you can create a test application to simulate a delayed backend API and use @SpringBootTest to create an integration test
@GetMapping("/test/delay") public ResponseEntity delay(int millis) throws InterruptedException
Any requests to /test/delay will be delayed by Thread.sleep(millis) pauses the execution of the API. Full application file can be found as the following
To create an integration test, use @SpringBootTest in conjunction with WebEnvironment.RANDOM_PORT and @LocalServerPort injected field to create a web test application context servlet based
@SpringBootTest( webEnvironment = WebEnvironment.RANDOM_PORT, classes = )
classes indicates the component classes to use for loading a Spring ApplicationContext
Run the tests
You can run the test cases with your IDE or Maven
$ mvn -Dtest=RestTemplate*TimeoutTest test
RestTemplate*TimeoutTest with a wildcard character represents for both test classes RestTemplateConnectTimeoutTest and RestTemplateReadTimeoutTest
All test cases should be passed except testReadTimeout2 as it is using restTemplateWithConnectTimeout which only Connect timeout is configured
The execution time of RestTemplate requests in the test cases should be greater than the timeout configuration value
Conclusion
In this tutorial, we learned to configure RestTemplate connection and read timeout in Spring and Spring Boot applications
We also learned to test Connect timeout by connecting a RestTemplate to a non-routable IP address or an existing host with a blocked port, and learn to test Read timeout by simulating a delayed backend controller by using Thread.sleep and write an integration test in Spring Boot by using @SpringBootTest
Giau Ngo
Giau Ngo is a software engineer, creator of HelloKoding. He loves coding, blogging, and traveling. You may find him on GitHub and LinkedIn