18

当响应为 5xx 时,我想在等待 10 秒后重试请求 3 次。但我没有看到可以使用的方法。在对象上

WebClient.builder()
                .baseUrl("...").build().post()
                .retrieve().bodyToMono(...)

我可以看到方法:

在有重试计数但没有延迟的条件下重试

.retry(3, {it is WebClientResponseException && it.statusCode.is5xxServerError} )

使用退避和次数重试,但没有条件

.retryBackoff 

还有一个retryWhen但是不知道怎么用

4

4 回答 4

26

使用 reactor-extra,您可以这样做:

.retryWhen(Retry.onlyIf(this::is5xxServerError)
        .fixedBackoff(Duration.ofSeconds(10))
        .retryMax(3))

private boolean is5xxServerError(RetryContext<Object> retryContext) {
    return retryContext.exception() instanceof WebClientResponseException &&
            ((WebClientResponseException) retryContext.exception()).getStatusCode().is5xxServerError();
}

更新: 使用新 API,相同的解决方案将是:

    .retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(10))
            .filter(this::is5xxServerError));

//...

private boolean is5xxServerError(Throwable throwable) {
    return throwable instanceof WebClientResponseException &&
            ((WebClientResponseException) throwable).getStatusCode().is5xxServerError();
}
于 2019-10-23T11:35:53.687 回答
8

您可以通过以下方法做到这一点:

  • 使用该exchange()方法获取没有异常的响应,然后在 5xx 响应上抛出一个特定的(自定义)异常(这与retrieve()总是抛出WebClientResponseExceptiona4xx5xx状态不同);
  • 在您的重试逻辑中拦截此特定异常;
  • 使用reactor-extra- 它包含一种retryWhen()用于更复杂和特定重试的好方法。然后,您可以指定在 10 秒后开始的随机退避重试,直至任意时间并尝试最多 3 次。(或者您当然可以使用其他可用的方法来选择不同的策略。)

例如:

//...webclient
.exchange()
.flatMap(clientResponse -> {
    if (clientResponse.statusCode().is5xxServerError()) {
        return Mono.error(new ServerErrorException());
    } else {
        //Any further processing
    }
}).retryWhen(
    Retry.anyOf(ServerErrorException.class)
       .randomBackoff(Duration.ofSeconds(10), Duration.ofHours(1))
       .maxRetries(3)
    )
);
于 2019-10-23T10:53:45.617 回答
6

我认为不推荐使用带有 Retry.anyOf 和 Retry.onlyIf 的 retryWhen。我发现这种方法很有用,它允许我们处理和抛出用户定义的异常。

例如 :

retryWhen(Retry.backoff(3, Duration.of(2, ChronoUnit.SECONDS))
                        .filter(error -> error instanceof UserDefinedException/AnyOtherException)
                        .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) ->
                                new UserDefinedException(retrySignal.failure().getMessage())))
于 2020-09-09T12:16:33.573 回答
2
// ...
.retryWhen(
    backoff(maxAttempts, minBackoff)
        .filter(throwable -> ((WebClientResponseException) throwable).getStatusCode().is5xxServerError()))
// ...
于 2020-09-13T19:48:48.473 回答