Spring WebClient:重试特定错误

时间:2019-10-23 10:35:24

标签: java spring spring-webflux project-reactor spring-webclient

我想在响应为5xx时等待10秒后重试请求3次。但我看不到可以使用的方法。在物体上

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

我可以看到方法:

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

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

重试,有退避次数和次数,但无条件

.retryBackoff 

还有一个retryWhen,但我不确定如何使用

4 个答案:

答案 0 :(得分:2)

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

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

例如:

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

答案 1 :(得分:1)

使用extra-reacter,您可以像这样操作

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

答案 2 :(得分:1)

// ...
.retryWhen(
    backoff(maxAttempts, minBackoff)
        .filter(throwable -> ((WebClientResponseException) throwable).getStatusCode().is5xxServerError()))
// ...

答案 3 :(得分:0)

不推荐使用retryWhen和Retry.anyOf和Retry.onlyIf。我发现这种方法很有用,它使我们能够处理和引发用户定义的异常。

例如:

retryWhen(Retry.backoff(3, Duration.of(2, ChronoUnit.SECONDS))
                        .filter(error -> error instanceof UserDefinedException/AnyOtherException)
                        .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) ->
                                new UserDefinedException(retrySignal.failure().getMessage())))