9

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?

Matt Raible
  • 8,187
  • 9
  • 61
  • 120
  • Looking at the source the `HttpComponentsAsyncClientHttpRequestFactory` ignores the `connectTimeout` and `readTimeout` properties. I'm not sure why. – M. Deinum Feb 23 '14 at 19:37
  • Hi. Sorry for the time, but can someone solve the problem? I have the same doubt like this: https://stackoverflow.com/questions/50594022/how-to-increase-timeout-asyncresttemplate-class – J. Abel May 30 '18 at 13:58

4 Answers4

5

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.

oskansavli
  • 313
  • 3
  • 6
4

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

Rossen Stoyanchev
  • 4,910
  • 23
  • 26
  • I also have similar question [here](http://stackoverflow.com/questions/29380653/how-to-properly-cancel-the-http-request-if-they-are-taking-too-much-time) which uses `AsyncRestTemplate` along with its `ListenableFuture` and I have few doubts on my problem which I am trying to accomplish. If possible, can you help me out over there. I am finding `AsyncRestTemplate` pretty cool since it uses NIO based connections. – john Apr 01 '15 at 18:49
3

I think the point of AsyncRestTemplate is the ListenableFuture (whose features you are not really using). So probably @Async is fine for your use case. Also, I think that results.get(5,TimeUnit.SECOND) is more efficient (and elegant) then looping with a Thread.sleep(...), but that's up to you I guess. Or maybe I'm missing something.

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • I also have similar question [here](http://stackoverflow.com/questions/29380653/how-to-properly-cancel-the-http-request-if-they-are-taking-too-much-time) which uses `AsyncRestTemplate` along with its `ListenableFuture` and I have few doubts on my problem which I am trying to accomplish. If possible, can you help me out over there whenever you get a chance. Any help is really appreciated. – john Apr 04 '15 at 09:06
  • I think it's a typo there. It should be `results.get(5,TimeUnit.SECONDS)` instead of `results.get(5,TimeUnit.SECOND)` – simomo Dec 04 '17 at 02:58
0
public CloseableHttpAsyncClient asyncHttpClient() {
    IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setConnectTimeout(getProperties().getConnectTimeout()).setSoTimeout(getProperties().getReadTimeout()).build()
    return  HttpAsyncClients.custom().setDefaultIOReactorConfig(ioReactorConfig).build();
}

like this, the AsyncRestTemplate timeout configurate is ok.