Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I set a timeout on Spring's AsyncRestTemplate?

I've setup a RestTemplate and an AsyncRestTemplate in my project similar to the following:

http://vincentdevillers.blogspot.fr/2013/10/a-best-spring-asyncresttemplate.html

I've noticed that the connect timeout doesn't actually work unless I change the httpRequestFactory() bean to be the following:

@Bean
public ClientHttpRequestFactory httpRequestFactory() {
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
    factory.setConnectTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS);
    factory.setReadTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS);
    return factory;
}

If I set DEFAULT_READ_TIMEOUT_MILLISECONDS to 5, a timeout occurs when I use restTemplate (as expected). However, when I use AsyncRestTemplate, a timeout doesn't occur. I've modified the asyncHttpRequestFactory() like httpRequestFactory(), but no dice.

@Bean
public AsyncClientHttpRequestFactory asyncHttpRequestFactory() {
    HttpComponentsAsyncClientHttpRequestFactory factory = new HttpComponentsAsyncClientHttpRequestFactory(asyncHttpClient());
    factory.setConnectTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS);
    factory.setReadTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS);
    return factory;
}

Here's how I'm attempting to use AsyncRestTemplate in a Spring MVC Controller:

String url = "...";
// Start the clock
long start = System.currentTimeMillis();

ListenableFuture<ResponseEntity<String>> results = asyncRestTemplate.getForEntity(url, String.class);
// Wait until the request is finished
while (!(results.isDone())) {
    Thread.sleep(10); //millisecond pause between each check
}
System.out.println("Elapsed time: " + (System.currentTimeMillis() - start));
return results.get().getBody();

How can I get AsyncRestTemplate to read my connection timeout settings?

On a related note, https://spring.io/guides/gs/async-method/ uses @Async and RestTemplate and seems to accomplish what I'm looking for. What's the advantage of using AsyncRestTemplate over RestTemplate?

like image 657
Matt Raible Avatar asked Feb 21 '14 19:02

Matt Raible


2 Answers

Very similar to the sync one:

final SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setTaskExecutor(new SimpleAsyncTaskExecutor());
requestFactory.setConnectTimeout(connectTimeout);
requestFactory.setReadTimeout(readTimeout);

final AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
asyncRestTemplate.setAsyncRequestFactory(requestFactory); 

From the source code, you can see that AsyncRestTemplate instance is created by using a SimpleClientHttpRequestFactory together with a SimpleAsyncTaskExecutor. So you can just do the same using a SimpleClientHttpRequestFactory instance whose timeout values are set.

like image 200
oskansavli Avatar answered Sep 20 '22 10:09

oskansavli


The AsyncRestTemplate relies on HTTP client's NIO capabilities so you can manage a large number of connections with a small number of threads. To achieve the same with @Async + RestTemplate would require much more resources. If you're only doing it in a few places then it's probably okay although even then AsyncRestTemplate, since it exists, is a little nicer and more specialized for the use case.

As for the read timeout it looks like it might be an oversight. Feel free to create a ticket. A quick look at this page, the "HttpAsyncClient configuration" example, shows using:

IOReactorConfig.custom().setConnectTimeout(30000).

I suppose you could give that a quick try

like image 35
Rossen Stoyanchev Avatar answered Sep 20 '22 10:09

Rossen Stoyanchev