I'm using Spring-boot-3
@GetExchange
with a WebClient
, sometimes we hit a following error:
java.lang.IllegalStateException: Timeout on blocking read for 5000000000 NANOSECONDS
What's the best practice, in case of using @GetExchange
to instruct the WebClient
to retry? There isn't enough documentation for this new annotation.
You need to use ExchangeFilterFunctions that will help you define your retry logic.
@Bean
FooClient fooClient() {
WebClient webClient =WebClient.builder()
.baseUrl("your_base_url")
.filter(withRetryableRequests())
.build();
HttpServiceProxyFactory factory=HttpServiceProxyFactory
.builder(WebClientAdapter.forClient(webClient))
.blockTimeout(Duration.of(HTTP_CLIENT_READ_TIMEOUT, ChronoUnit.SECONDS)) // Configure how long to wait for a response for an HTTP service method with a synchronous (blocking) method signature.By default this is 5 seconds.
.build();
return factory.createClient(FooClient.class);
}
private ExchangeFilterFunction withRetryableRequests() {
return (request, next) -> next.exchange(request)
.flatMap(clientResponse -> Mono.just(clientResponse)
.filter(response -> clientResponse.statusCode().isError())
.flatMap(response -> clientResponse.createException())
.flatMap(Mono::error)
.thenReturn(clientResponse))
.retryWhen(this.retryBackoffSpec());
}
private RetryBackoffSpec retryBackoffSpec() {
return Retry.backoff(3, Duration.ofSeconds(2))
.filter(throwable->throwable instanceof WebClientResponseException) // here filter on the errors for which you want a retry
.doBeforeRetry(retrySignal -> log.warn("Retrying request after following exception : {}", retrySignal.failure().getLocalizedMessage()))
.onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> retrySignal.failure());
}
[EDIT] For the particular case that you encounter, i.e. the exception
java.lang.IllegalStateException: Timeout on blocking read for 5000000000 NANOSECONDS
the probable cause is that your service is waiting for the answer to the request and after 5 seconds (by default), the service hangs up.
It would be necessary to increase the read timeout of the http client used. I have edited the code accordingly with a comment on the line concerned.