youngturtle
youngturtle

Reputation: 33

Spring webclient - increase timeout duration after each retry

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

Answers (2)

Michael Berry
Michael Berry

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

Amit
Amit

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

Related Questions