【问题标题】:Spring WebClient multiple retryWhen to handle different errorsSpring WebClient 多次重试时处理不同的错误
【发布时间】:2020-09-17 20:23:24
【问题描述】:

我可以添加多个retryWhen 来执行重试以处理不同的WebClient 故障响应

我想要达到的目标:

我正在使用 WebClient 进行 REST API 调用。很少有错误场景,发生时我需要执行重试,但延迟不同。

例如, 1.如果发生401 Unauthorize,我可以在刷新令牌后立即重试。 2.如果发生502/503 Server错误,我需要延迟5秒后重试。 3.如果429 Too Many Request发生,我需要再延迟重试,比如20秒之后。

我想创建如下重试规范:

    protected static final Predicate<Throwable> is401 =
                (throwable) -> throwable instanceof WebClientResponseException.Unauthorized;

        protected static final Predicate<Throwable> is5xx =
                (throwable) -> throwable instanceof WebClientResponseException.ServiceUnavailable;

        protected static final Predicate<Throwable> is429 =
                (throwable) -> throwable instanceof WebClientResponseException.TooManyRequests;

        Retry retry401 = Retry.fixedDelay(5, Duration.ofSeconds(1))
                    .filter(is401)
                    .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> retrySignal.failure());

        Retry retry5xx = Retry.fixedDelay(5, Duration.ofSeconds(10))
                    .filter(is5xx)
                    .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> retrySignal.failure());

        Retry retry429 = Retry.fixedDelay(5, Duration.ofSeconds(20))
                    .filter(is429)
                    .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> retrySignal.failure());

// trying to apply the to WebClient like below:
    WebClient.Builder()
        .get()
        .uri("endpointuri")
        .retrieve()
        .bodyToFlux(String.class)
        .retryWhen(retry401)
        .retryWhen(retry5xx)
        .retryWhen(retry429);

看起来 `.retryWhen(retry429)' 会覆盖其他重试。

【问题讨论】:

  • 那么,如果您获得 401,500,401,429,您期望会发生什么?应该重置吗?它应该对每个错误进行计数吗?

标签: spring-boot project-reactor spring-webclient spring-reactive


【解决方案1】:

看起来 `.retryWhen(retry429)' 会覆盖其他重试。

这是错误的。 retryWhen 是一个基于现有发布者的复合运算符 - 您可以将其链接多次。您唯一需要担心一次重试“覆盖”另一次的情况是当您的 filter 谓词重叠时。

即使在这种情况下,它看起来也是“第一次获胜”(在链中)而不是“最后一次获胜”。

您的问题可能与此行有关:

protected static final Predicate<Throwable> is5xx =
            (throwable) -> throwable instanceof WebClientResponseException.ServiceUnavailable;

根据您的命名和描述,您似乎希望它捕获任何 5xx 错误 - 但它只会捕获 503(专门分配给“服务不可用”。)

如果您尝试使用不同的东西,例如 502 或 500 错误 - 那么您定义的所有谓词(因此重试)都不会匹配。

相反,要检查任何 5xx 错误,您可能需要:

protected static final Predicate<Throwable> is5xx =
        (throwable) -> throwable instanceof WebClientResponseException && ((WebClientResponseException)throwable).getStatusCode().is5xxServerError();

【讨论】:

    猜你喜欢
    • 2021-08-06
    • 2019-12-04
    • 2020-06-03
    • 2018-12-21
    • 2021-06-13
    • 2021-09-25
    • 2020-11-04
    • 2018-08-18
    • 2022-01-26
    相关资源
    最近更新 更多