Reputation: 33
I am looking for a way to increase the duration of the timeout after successive retries on webclient calls.
For example, I want the first request to timeout after 50ms, the first retry will then timeout after 500ms, and a second and final retry to have a timeout duration of 5000ms.
I am not sure how to go about doing this. I am only aware of how to set the timeout value to a fixed duration for all retries.
ex.
public Flux<Employee> findAll()
{
return webClient.get()
.uri("/employees")
.retrieve()
.bodyToFlux(Employee.class)
.timeout(Duration.ofMillis(50))
.retry(2);
}
Upvotes: 3
Views: 1963
Reputation: 72254
You can abstract out your backoff & timeout logic into a separate utility function, then simply call transform()
on your publisher.
In your case, it looks like you're after basic backoff functionality - take an initial timeout value, then multiply it by a factor until we reach a maximum. We can implement this like so:
public <T> Flux<T> retryWithBackoffTimeout(Flux<T> flux, Duration timeout, Duration maxTimeout, int factor) {
return mono.timeout(timeout)
.onErrorResume(e -> timeout.multipliedBy(factor).compareTo(maxTimeout) < 1,
e -> retryWithBackoffTimeout(mono, timeout.multipliedBy(factor), maxTimeout, factor));
}
...but this can of course be any kind of timeout logic you like.
With that utility function in place, your findAll()
method becomes:
public Flux<Employee> findAll()
{
return webClient.get()
.uri("/employees")
.retrieve()
.bodyToFlux(Employee.class)
.transform(m -> retryWithBackoffTimeout(m, Duration.ofMillis(50), Duration.ofMillis(500), 10));
}
Upvotes: 1
Reputation: 703
Have you explored the @Retryable? If not then here is the option. Add this dependencies
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
Annotate your Main Class
@EnableRetry
public class MainClass{
...
}
Then annotate your transaction which is invoking the call
public interface BackendAdapter {
@Retryable(
value = {YourCustomException.class},
maxAttempts = 4,
backoff = @Backoff(random = true, delay = 1000, maxDelay = 5000, multiplier = 2)
)
public String getBackendResponse(boolean simulateretry, boolean simulateretryfallback);
}
if you set delay to 1000ms, maxDelay to 5000ms and multipler to a value of 2 then the retry time will look something like the following for 4 attempts:
Retry 1 — 1605
Retry 2 — 2760
Retry 3 — 7968
Retry 4 — 14996
Upvotes: 0