简体   繁体   English

Spring WebClient 的自定义重试策略

[英]Custom Retry strategy for Spring WebClient

I'm using a fixedRetry in order to repeat HTTP calls using WebClient.我正在使用 fixedRetry 以使用 WebClient 重复 HTTP 调用。 I want the first retry to be called after 5 minutes, the second one after 30 minutes, and the rest after 60 minutes.我希望在 5 分钟后调用第一次重试,在 30 分钟后调用第二次,在 60 分钟后调用 rest。 Is there a way to do this using the fixedRetry?有没有办法使用fixedRetry来做到这一点? I checked https://www.baeldung.com/spring-webflux-retry several times, but I haven't found a way to use 3 different values for the delay time.我检查了https://www.baeldung.com/spring-webflux-retry几次,但我还没有找到一种方法来使用 3 个不同的延迟时间值。

This how the constructor looks like:这是构造函数的样子:

public MyService(WebClient client,
            @Value("${retry.quantity}") int retries,
            @Value("${retry.time.first}") int firstTime,
            @Value("${retry.time.second}") int secondTime,
            @Value("${retry.time.rest}") int restTime) 
{
        this.client = client;
        this.fixedRetry = Retry.anyOf(ResponseException.class)
                .fixedBackoff(Duration.ofSeconds(restTime))
                .retryMax(retries)
                .doOnRetry(exception ->
                    log.error("Exception on Retry is {} .", exception)
                );
}

You would need to implement custom Retry to achieve this.您需要实施自定义Retry来实现这一点。 Here is an example这是一个例子

private static class CustomRetrySpec extends Retry {
    private final int retries;
    private final Duration firstTime;
    private final Duration secondTime;
    private final Duration restTime;

    public CustomRetrySpec(int retries, Duration firstTime, Duration secondTime, Duration restTime) {
        this.retries = retries;
        this.firstTime = firstTime;
        this.secondTime = secondTime;
        this.restTime = restTime;
    }

    @Override
    public Publisher<?> generateCompanion(Flux<RetrySignal> retrySignals) {
        return retrySignals.flatMap(this::getRetry);
    }

    private Mono<Long> getRetry(Retry.RetrySignal rs) {
        if (rs.totalRetries() < retries) {
            Duration delay;
            if (rs.totalRetries() == 0) {
                delay = firstTime;
            } else if (rs.totalRetries() == 1) {
                delay = secondTime;
            } else {
                delay = restTime;
            }

            log.debug("retry {} with backoff {}min", rs.totalRetries(), delay.toMinutes());
            return Mono.delay(delay)
                    .thenReturn(rs.totalRetries());
        } else {
            log.debug("retries exhausted with error: {}", rs.failure().getMessage());
            throw Exceptions.propagate(rs.failure());
        }
    }
}

Here is a test using StepVerifier.withVirtualTime这是使用StepVerifier.withVirtualTime的测试

@Test
void testCustomRetrySpec() {
    StepVerifier.withVirtualTime(() ->
                    process()
                            .retryWhen(new CustomRetrySpec(3,
                                    Duration.ofMinutes(5),
                                    Duration.ofMinutes(30),
                                    Duration.ofMinutes(60))
                            )
            )
            .expectSubscription()
            .expectNoEvent(Duration.ofMinutes(5))
            .expectNoEvent(Duration.ofMinutes(30))
            .expectNoEvent(Duration.ofMinutes(60))
            .expectError()
            .verify();

}

private Mono<?> process() {
    return Mono.error(new RuntimeException("oops"));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM