Spring Boot — How to set a Request Timeout for a REST API

Nilesh Mahant
9 min readNov 5, 2023

--

Imagine that you are running a website that uses a REST API to serve its content. If a user requests a page, the website will send a request to the API. If the API does not respond within a certain amount of time, the website will not be able to load the page and the user will see an error message.

Setting a request timeout for your API can help to prevent this from happening. If a request takes longer than the timeout to complete, the API will automatically return a response indicating that the request has timed out. This will allow the website to load the page even if the API is slow or unresponsive.

Request timeouts can also help to protect your API from malicious attacks. Some attackers may try to send long-running requests to your API in order to overwhelm it and cause it to become unresponsive. By setting a request timeout, you can prevent these attacks from being successful.

There are a few different ways to set a request timeout in Spring Boot. One way is to use the spring.mvc.async.request-timeout property in your application properties file. This property sets a global timeout for all incoming connections. Another way to set a request timeout is to use the WebClient.timeout() method. This method allows you to set a timeout for individual web requests. We will explore several built-in methods of setting timeout.

If you need more flexibility, you can also use a third-party library such as Resilience4j, Failsafe or Microprofile / SmallRye Fault Tolerance. These libraries provide a variety of features, including timeouts. We will explore the use of these libraries.

Built-in features for timeout

Property — spring.mvc.async.request-timeout

This property sets a global timeout for all asynchronous requests. To set this property, add it to your application properties file (e.g., application.properties or application.yml). The value of the property should be in milliseconds. For example, to set a timeout of 5 seconds, you would add the following property:

spring.mvc.async.request-timeout=5000

If this value is not set, the default timeout of the underlying implementation is used.

Use server specific application properties

According to the documentation from Spring Boot version 2.3 onwards server.connection-timeout property is removed. Each server behaves differently, so server specific properties are recommended. By default, Spring Boot embeds tomcat (if you haven’t configured it to use jetty, netty or something else), so you can use the server.tomcat.connection-timeout property to set the timeout.

server.tomcat.connection-timeout //for tomcat
server.netty.connection-timeout //for netty
server.jetty.connection-idle-timeout //for jetty

You can read here on other server related properties.

Using the @Transactional annotation

This annotation can be used to set a timeout for individual database operations. To do this, set the timeout attribute of the annotation. The value of the attribute should be in seconds. For example, to set a timeout of 30 seconds, you would use the following annotation:

@Transactional(timeout=30)
public void myDatabaseOperation() {
// …
}

Webflux — WebClient.timeout()

Spring 5.0 introduced the reactive-stack web framework — Webflux. WebFlux is built on the Reactor library. It provides a non-blocking and asynchronous programming model that can help you to build responsive and scalable web applications.

WebClient is a reactive HTTP client that is included in WebFlux. It provides a fluent and declarative API for making HTTP requests and receiving responses. WebClient is also non-blocking and asynchronous, which makes it ideal for use in reactive applications.

Imagine that you are running a website that uses a REST API to serve its content. If you are using a traditional blocking web framework, such as Spring MVC, each request to your API will block a thread until the response is received. This can lead to performance problems if your API receives a lot of traffic.

WebFlux and WebClient can help you to solve this problem by providing a non-blocking and asynchronous programming model. When a request is made to your API using WebClient, a new thread is not created. Instead, the request is handled by a reactor loop, which is a pool of threads that can handle multiple requests concurrently. This allows your API to handle a large number of requests without blocking.

WebClient.timeout() is a method provided by the Spring WebClient API to set a timeout for individual web requests. This can be useful for preventing your API from becoming unresponsive due to long-running requests, such as those that are caused by network congestion or server problems.

The following code shows how to use the WebClient.timeout() method to set a timeout of 5 seconds for a web request:

WebClient webClient = new WebClient();
Flux<String> response = webClient.get()
.uri("https://example.com/api/endpoint")
.retrieve()
.bodyToFlux(String.class)
.timeout(Duration.ofSeconds(5))
.onErrorResume(ConnectTimeoutException.class, ex -> {
// Handle timeout
});

If the request takes longer than 5 seconds to complete, the timeout() method will throw a ConnectTimeoutException. You can handle this exception in your code to return an appropriate response to the client.

The WebClient.timeout() method allows you to set a timeout for individual web requests. This is more flexible than using a global timeout, which can be too restrictive in some cases. You can specify the timeout value in milliseconds, which gives you precise control over how long a request is allowed to take.

Third-party libraries

MicroProfile Fault Tolerance

MicroProfile Fault Tolerance is a lightweight library that provides a standard way to implement fault tolerance patterns in Java applications. It includes support for timeouts, retries, circuit breakers, and bulkheads.

To add the MicroProfile Fault Tolerance library to your Spring Boot project, you can use the following dependency in your pom.xml file:

<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile-fault-tolerance</artifactId>
<version>4.0</version>
</dependency>

Once you have added the dependency, you can use the MicroProfile Fault Tolerance annotations to implement fault tolerance in your Spring Boot application.

To set a request timeout using MicroProfile Fault Tolerance, you can use the @Timeout annotation. The annotation takes a value in milliseconds, which is the maximum amount of time that the method invocation is allowed to take. If the method invocation takes longer than the timeout, a TimeoutException is thrown.

For example, the following code shows a method that uses the @Timeout annotation to set a request timeout of 5 seconds:

@Timeout(5000)
public String myMethod() throws Exception {
// Do some work that may take a long time
}

For more information on how to use the MicroProfile Fault Tolerance library, please see the official documentation.

Microprofile Fault Tolerance version 4 supports Java 8 or higher.

SmallRye Fault Tolerance

SmallRye Fault Tolerance is an implementation of the MicroProfile Fault Tolerance specification. It provides a declarative, annotation-based API for guarding method calls.

To add the SmallRye Fault Tolerance library to your Spring Boot project, you can use the following dependency in your pom.xml file:

<dependency>
<groupId>io.smallrye</groupId>
<artifactId>smallrye-fault-tolerance</artifactId>
<version>6.2.0</version>
</dependency>

Once you have added the dependency, you can use the SmallRye Fault Tolerance annotations to implement fault tolerance in your Spring Boot application.

The following code shows how to use the @Timeout annotation to set a timeout of 5 seconds for a method invocation.

@Timeout(5000)
public String myMethod() throws Exception {
// Do some work that may take a long time
return "Hello!";
}

If the method invocation takes longer than 5 seconds to complete, the SmallRye Fault Tolerance library will automatically throw a TimeoutException.

For more information on how to use the SmallRye Fault Tolerance library, please see the official documentation.

Smallrye Fault Tolerance version 6.2.0 supports Java 11 or higher.

Resilience4j

Resilience4j is a lightweight fault tolerance library designed for functional programming. It provides higher-order functions (decorators) to enhance any functional interface, lambda expression or method reference with a Circuit Breaker, Rate Limiter, Retry or Bulkhead.

To add Resilience4j to your Spring Boot project, you can use the following dependency in your pom.xml file:

<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-all</artifactId>
<version>3.1.8</version>
</dependency>

There are two ways to set a timeout on a REST API using Resilience4j:

1. Using the TimeoutDecorator

This is the preferred way to set a timeout on a REST API using Resilience4j. The TimeoutDecorator can be used to decorate any functional interface, lambda expression, or method reference. To use the TimeoutDecorator, you first need to create a CircuitBreaker instance. Then, you can use the TimeoutDecorator.of() method to create a new TimeoutDecorator instance with the desired timeout value. Finally, you can use the TimeoutDecorator.executeSupplier() method to execute the functional interface, lambda expression, or method reference with the timeout applied.

Here is an example of how to use the TimeoutDecorator to set a timeout of 5 seconds on a REST API request:

import io.github.resilience4j.core.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.decorators.TimeoutDecorator;

public class MyService {

private final CircuitBreaker circuitBreaker;

public MyService(CircuitBreaker circuitBreaker) {
this.circuitBreaker = circuitBreaker;
}

public String myMethod() throws Exception {
TimeoutDecorator timeoutDecorator = TimeoutDecorator.of(circuitBreaker, 5000);

return timeoutDecorator.executeSupplier(() -> {
// Do some work that may take a long time
return "Hello!";
});
}
}

2. Using the @TimeLimiter annotation

The @TimeLimiter annotation can be used to annotate a method to set a timeout on the method invocation. To use the @TimeLimiter annotation, you first need to create a TimeLimiter instance. Then, you can annotate the method with the @TimeLimiter annotation and specify the desired timeout value.

Here is an example of how to use the @TimeLimiter annotation to set a timeout of 5 seconds on a REST API request:

import io.github.resilience4j.timelimiter.TimeLimiter;
@TimeLimiter(name = "myTimeLimiter", timeoutDuration = 5000)
public String myMethod() throws Exception {
// Do some work that may take a long time
return "Hello!";
}

Once the method is annotated with the @TimeLimiter annotation, Resilience4j will automatically set a timeout on the method invocation. If the method invocation takes longer than the timeout value to complete, Resilience4j will throw a TimeoutException.

If you need to set a timeout on a single method invocation, then you can use the @TimeLimiter annotation. If you need to set a timeout on multiple method invocations, then you can use the TimeoutDecorator.

Resilience4j requires Java 17 or higher.

Failsafe

Failsafe is a lightweight, zero-dependency library for handling failures in Java. It provides a concise API for handling everyday use cases and the flexibility to handle everything else. Failsafe works by wrapping executable logic with one or more resilience policies, which can be combined and composed as needed. Policies include Retry, CircuitBreaker, RateLimiter, Timeout, Bulkhead, and Fallback.

To add Failsafe as a dependency in your Maven project, you need to add the following dependency to your pom.xml file:

<dependency>
<groupId>net.jodah</groupId>
<artifactId>failsafe</artifactId>
<version>3.2.1</version>
</dependency>

There are two ways to set a timeout on a REST API using Failsafe

1. Using the FailsafeExecutor

The FailsafeExecutor can be used to execute any code block, including method invocations, lambda expressions, and functional interfaces. To set a timeout on a REST API request using the FailsafeExecutor, you can use the following steps:

  1. Create a FailsafeExecutor instance
  2. Use the Failsafe.with() method to create a new Failsafe instance with the desired timeout value.
  3. Use the failsafeExecutor.get() method to execute the REST API request with the timeout applied.

Here is an example of how to set a timeout of 5 seconds on a REST API request using the FailsafeExecutor:

import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.FailsafeExecutor;
public class MyService {
private final FailsafeExecutor failsafeExecutor;

public MyService() {
this.failsafeExecutor = Failsafe.withTimeout(5000);
}

public String myMethod() throws Exception {
return failsafeExecutor.get(() -> {
// Make a REST API request
return "Hello!";
});
}
}

2. Using the @Retryable annotation

The @Retryable annotation can be used to annotate a method to set a timeout on the method invocation. To set a timeout on a REST API request using the @Retryable annotation, you can use the following steps:

  1. Create a RetryPolicy instance.
  2. Annotate the method with the @Retryable annotation and specify the desired timeout value.
  3. Use reflection to invoke the method.

Here is an example of how to set a timeout (with retry) on a REST API request using the @Retryable annotation:

import org.springframework.retry.RetryPolicy;
import org.springframework.retry.annotation.Retryable;
import org.springframework.web.client.RestTemplate;

public class MyService {
private final RestTemplate restTemplate;

public MyService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@Retryable(value = {RestClientException.class}, maxAttempts = 3, timeout = 5000L)
public ResponseEntity<String> getResponse() {
return restTemplate.exchange("http://localhost:8080/api/test", HttpMethod.GET, null, String.class);
}
}

This code will create a new RetryPolicy instance and specify that the method should be retried up to 3 times if a RestClientException is thrown. If the method still fails after 3 retries, or if the timeout is reached, the method will throw an ExhaustedRetryException.

To invoke the method, we can use reflection:

import java.lang.reflect.Method;
public class MyApplication {
public static void main(String[] args) throws Exception {
MyService myService = new MyService(new RestTemplate());
Method getResponseMethod = myService.getClass().getMethod("getResponse");

// Invoke the method with reflection
ResponseEntity<String> response = (ResponseEntity<String>) getResponseMethod.invoke(myService);
System.out.println(response.getStatusCode());
}
}

This code will invoke the getResponse() method and print the response status code to the console.

Note: The @Retryable annotation can be used to retry any method, not just REST API requests. It is a powerful tool for handling transient failures and improving the resilience of your application.

If you need to set a timeout on a single method invocation, then you can use the @Retryable annotation. If you need to set a timeout on multiple method invocations, then you can use the FailsafeExecutor.

Failsafe requires Java 8 or higher.

Setting timeouts on REST APIs is an important part of building resilient and responsive applications. Spring Boot provides a few built-in mechanisms for setting timeouts, but third-party libraries provide more flexibility and features.

--

--

No responses yet