弹簧 Web 客户端:在特定错误时使用回退重试

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

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

我可以看到方法:

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

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

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

.retryBackoff 

还有一个,但我不知道如何使用它retryWhen


答案 1

使用反应堆额外,你可以这样做:

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

答案 2

您可以采用以下方法执行此操作:

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

例如:

//...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)
    )
);

推荐