Skip to main content

Set Read Timeout Dynamically

warning

Stop using this feature!

Spring does not support setting a separate read timeout for each request. The implementation of this feature is too hacky, it will be removed in version 3.5.0.

Spring does not provide a way to set the read timeout dynamically, see issue. This framework provides EnhancedJdkClientHttpRequestFactory to support this feature.

note

This feature needs to use EnhancedJdkClientHttpRequestFactory as the ClientHttpRequestFactory implementation, and this is the default behavior.

To avoid changing Spring's default behavior, starting from version 3.2.4, the HttpClientCustomizer interface was added. It no longer uses EnhancedJdkClientHttpRequestFactory as the default implementation but instead uses the built-in JdkClientHttpRequestFactory. To use EnhancedJdkClientHttpRequestFactory, it must be explicitly configured in HttpClientCustomizer.

// For RestClient
@Bean
HttpClientCustomizer.RestClientCustomizer restClientCustomizer() {
return (client, channel) -> {
EnhancedJdkClientHttpRequestFactory requestFactory = new EnhancedJdkClientHttpRequestFactory();
requestFactory.setReadTimeout(channel.getReadTimeout());
client.requestFactory(requestFactory);
};
}

// For RestTemplate
@Bean
HttpClientCustomizer.RestTemplateCustomizer restTemplateCustomizer() {
return (client, channel) -> {
EnhancedJdkClientHttpRequestFactory requestFactory = new EnhancedJdkClientHttpRequestFactory();
requestFactory.setReadTimeout(channel.getReadTimeout());
client.setRequestFactory(requestFactory);
};
}

There are two ways to set the read timeout dynamically.

Use RequestConfigurator Interface

@HttpExchange("/users")
interface UserApi extends RequestConfigurator<UserApi> {
@GetExchange
List<User> list();
}

@Service
class UserService {
@Autowired
UserApi userApi;

List<User> listWithTimeout(int timeout) {
return userApi.withTimeout(timeout).list();
}
}

Each time the RequestConfigurator method is called, a new proxy client will be created, and it inherits the original configuration and will not affect the original configuration.

info

RequestConfigurator is suitable for client-side use but not for defining a neutral API. Therefore, Requester is provided for a programmatic way to dynamically set the read timeout.

Use Requester Class

List<User> users = Requester.create()
.withTimeout(10000)
.addHeader("X-Foo", "bar")
.call(() -> userApi.list());

Reactive Client

For WebClient client type, use timeout method to set the read timeout for each request.

Flux<User> users = userApi.list().timeout(Duration.ofSeconds(10));