【问题标题】:Webflux Webclient re-try with different URLWebflux Webclient 使用不同的 URL 重试
【发布时间】:2020-10-01 09:44:15
【问题描述】:

我正在使用 webclient 进行其余调用,我需要的是,如果主 URL 第 n 次失败,请在 Secondary URL 上重试。请在下面找到我正在使用的逻辑的示例代码。但是,一旦创建了client,我们似乎就无法更改 URL,即使我更改了 URL,它也不会生效,并且仍然会向初始 URL 发起请求。

ClientHttpConnector connector;//initiate
WebClient webClient = WebClient.builder().clientConnector(connector).build();
WebClient.RequestBodyUriSpec client = webClient.post();

client.uri("http://primaryUrl/").body(BodyInserters.fromObject("hi")).retrieve().bodyToMono(String.class).retryWhen(Retry.anyOf(Exception.class)
                    .exponentialBackoff(Duration.ofSeconds(2), Duration.ofSeconds(10)).doOnRetry(x ->
                    {
                        if (x.iteration() == 2) {
                            client.uri("http://fail_over_url/");//this does not work
                        }
                    })
                    .retryMax(2)).subscribe(WebClientTest::logCompletion, WebClientTest::handleError);

有什么方法可以在重试周期的中间更改 URL 吗?

【问题讨论】:

    标签: java spring spring-boot spring-webflux


    【解决方案1】:

    但似乎一旦创建了客户端,我们就无法更改 URL

    你不能——它是不可变的。

    即使我更改了网址,它也不会生效

    您实际上并没有更改 URL。看看uri() 方法 - 它返回一个带有 URI 集的 new 实例。由于您没有对新实例执行任何操作,因此没有任何反应(如预期的那样)。

    我可能建议的路线是创建一个单独的方法来形成并返回您的基本 WebClient 发布者:

    private Mono<String> fromUrl(String url) {
        return WebClient.builder().clientConnector(connector).build()
                .post()
                .body(BodyInserters.fromValue("hi"))
                .uri(url)
                .retrieve()
                .bodyToMono(String.class);
    }
    

    ...然后执行以下操作:

    fromUrl("https://httpstat.us/400").retryWhen(Retry.backoff(2, Duration.ofSeconds(1)))
            .onErrorResume(t -> Exceptions.isRetryExhausted(t), t -> fromUrl("https://httpstat.us/500").retryWhen(Retry.backoff(5, Duration.ofSeconds(1))))
            .onErrorResume(t -> Exceptions.isRetryExhausted(t), t -> fromUrl("https://httpstat.us/200").retryWhen(Retry.backoff(7, Duration.ofSeconds(1))))
    

    ...它将尝试/400 3 次,然后尝试/500 5 次,然后最多尝试/200 7 次(但除非它关闭,否则当然会在第一次尝试时返回。)

    请注意,上面的示例使用了具有内置重试功能的最新版本的 reactor-core,而不是 reactor 插件中的重试功能。将其转换为反应堆插件功能应该相当简单。

    这并没有在相同重试周期中严格更改 URL,而是将请求与每个请求的可配置重试链接在一起。然后,这允许您在不同的 URL 上设置不同的重试策略,如果您不一定希望重试从其前一点“继续”,这是有利的(将退避设置回一秒以重新开始可能是有意义的例如,网址。)

    【讨论】:

    • 您使用的是什么版本的 Reactor + 插件?我的 ide 中存在大量错误,用于静态引用和错误的方法签名。 connector 是从哪里来的 fromUrl,它不需要传入,还是你假设它在课堂上是全局的?
    • @123 最新版本的反应堆核心 - 不再需要附加组件,包含所有内置的重试内容。(假设连接器是全局的,因为问题不会在任何地方实例化它,但这很简单如果不是,则更改。)
    • 啊,实际上两者都在测试项目中。看起来 extras 是首先在导入中,所以需要完整路径。此外,我认为 OP 仍在使用附加功能,因为他们使用 anyOf,这不在核心 Retry 中。
    • @123 好点——这会教我如何着急……我会在答案中澄清这一点。
    • 感谢@MichaelBerry,完美答案。
    猜你喜欢
    • 2020-07-30
    • 2020-05-18
    • 2018-05-09
    • 2019-09-19
    • 1970-01-01
    • 2023-02-05
    • 1970-01-01
    • 2020-01-30
    • 2020-12-31
    相关资源
    最近更新 更多