Spring webclient - 每次重试后增加超时持续时间

Spring webclient - increase timeout duration after each retry

我正在寻找一种方法来增加连续重试 webclient 调用后的超时持续时间。

例如,我希望第一次请求在 50 毫秒后超时,第一次重试将在 500 毫秒后超时,第二次也是最后一次重试的超时持续时间为 5000 毫秒。

我不知道该怎么做。我只知道如何将所有重试的超时值设置为固定持续时间。

例如

public Flux<Employee> findAll() 
{
    return webClient.get()
        .uri("/employees")
        .retrieve()
        .bodyToFlux(Employee.class)
        .timeout(Duration.ofMillis(50))
        .retry(2);
}

你探索过@Retryable了吗?如果没有,那么这里是选项。添加此依赖项

<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>

注释您的 Main Class

@EnableRetry
public class MainClass{
    ...
}

然后注释调用调用的事务

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);
 }

如果您将延迟设置为 1000 毫秒,将最大延迟设置为 5000 毫秒,并将倍增器设置为值 2,则重试时间将类似于以下 4 次尝试:

Retry 1 — 1605
Retry 2 — 2760
Retry 3 — 7968
Retry 4 — 14996

您可以将退避和超时逻辑抽象到一个单独的实用程序函数中,然后只需在您的发布商上调用 transform()

在您的情况下,您似乎在追求基本的退避功能 - 获取初始超时值,然后将其乘以一个因子,直到达到最大值。我们可以这样实现:

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));
}

...但这当然可以是您喜欢的任何类型的超时逻辑。

有了这个效用函数,你的 findAll() 方法就变成了:

public Flux<Employee> findAll()
{
    return webClient.get()
            .uri("/employees")
            .retrieve()
            .bodyToFlux(Employee.class)
            .transform(m -> retryWithBackoffTimeout(m, Duration.ofMillis(50), Duration.ofMillis(500), 10));
}