Reputation: 49
I am using Spring boot Webflux 2.4.4 (latest) and trying to invoke a backend URL using WebClient. WebClient always responds above 20 secs. If I hit the URL directly it responds in milliseconds.
Pom Looks below:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Code looks as Below:
@RestController
public class Controller {
@GetMapping("/test")
public Mono<String> test() {
long startMillis = System.currentTimeMillis();
return webClient().get().uri("https://www.google.com").exchangeToMono(response -> {
System.out.println("Elapsed Time is: " + (System.currentTimeMillis() - startMillis));
if (response.statusCode().equals(HttpStatus.OK)) {
return Mono.just("OK");
}
return Mono.just("OK");
});
}
private WebClient webClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(HttpClient
.create().secure().responseTimeout(Duration.ofMillis(1000))
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000).doOnConnected(c -> c
.addHandlerLast(new ReadTimeoutHandler(3)).addHandlerLast(new WriteTimeoutHandler(3)))))
.build();
}
}
Kindly suggest what I am missing or doing wrong.
Upvotes: 2
Views: 6078
Reputation: 72254
The timeouts which I have configured seem no effect.
You've set a variety of arbitrary timeouts here, all that do different things:
ReadTimeoutHandler
is triggered when no data is read in the given time window. So if any data, however slow, is still being read in that 3 second window, it won't trigger.WriteTimeoutHandler
gives a certain time window for a write to complete - but unless the underlying request that you're sending (not waiting for the response) takes more than that time, this won't trip either.CONNECT_TIMEOUT_MILLIS
is the time it takes to actually establish a TCP connection, before any data is sent. So again, unless that takes over 3 seconds, it won't trip.responseTimeout()
is the time it takes to read a full response after sending the request. So note that this doesn't include any DNS resolution, warmup time, etc. that could be needed before the request is sent.I'm not sure why it's taking over 20 seconds for you - that seems ridiculously long, the whole request executes on my moderately powered machine on my average internet connection in a few hundred ms at most. The cause of that could be anything from a very slow machine, slow internet connection, slow DNS servers, slow network, slow proxy, etc. - but it's not a problem with the code you have there.
If you want a timeout for the whole chain to execute, including any background requests, warmup time etc. that it might take - then AFAIK the only way of achieving that is on the mono itself - so your request then becomes:
return webClient()
.get()
.uri("https://www.google.com")
.exchangeToMono(
response -> {
System.out.println("Elapsed Time is: " + (System.currentTimeMillis() - startMillis));
if (response.statusCode().equals(HttpStatus.OK)) {
return Mono.just("OK");
}
return Mono.just("OK");
})
.timeout(Duration.ofMillis(500)); //Timeout specified here
Upvotes: 8