When configuring RestTemplate timeout, there're two settings 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 read

Configure RestTemplate timeout

In Spring Boot, the connection and read timeout can be configured via RestTemplateBuilder

static final int TIMEOUT = 500;

@Bean
RestTemplate restTemplateWithConnectReadTimeout() {  
    return new RestTemplateBuilder()
        .setConnectTimeout(Duration.ofMillis(TIMEOUT))
        .setReadTimeout(Duration.ofMillis(TIMEOUT))
        .build();
}

If your project doesn't use Spring Boot, you can configure them via SimpleClientHttpRequestFactory

static final int TIMEOUT = 500;

@Bean
RestTemplate restTemplateTimeoutConfigWithRequestFactory() {  
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setConnectTimeout(TIMEOUT);
    requestFactory.setReadTimeout(TIMEOUT);

    return new RestTemplate(requestFactory);
}

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 {  
    Thread.sleep(millis);

    return ResponseEntity.ok().build();
}

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 = {RestTemplateWithTimeoutConfig.class, RestTemplateWithTimeoutTestApplication.class}
)

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

You can find the full source code on GitHub