使用Spring WebFlux中的webclient在Mono上有条件重复或重试

时间:2019-04-30 14:39:07

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

我想做的是在带有Webclient的Webflux中的Mono上有条件重复。情况如下:

我们有一些商务休息服务服务,可返回生成的文档。此文档的生成是由在此之前调用的另一服务触发的。但是,回到正题:文档生成服务需要10到30秒。我们要做的是:10秒钟后检查是否生成文档(单声道)。如果是这样,一切都很好。如果不是,请在5秒钟后重复(或重试)并检查是否生成了文档。依此类推,直到(最坏的情况)在30秒后超时。这可能吗?一些(伪)代码:

return this.webClient.post().uri(SERVICE_URL)).        
body(BodyInserters.fromObject(docRequest)).retrieve().
bodyToMono(Document.class).
delaySubscription(Duration.ofSeconds(10)).
repeat5TimesWithDynamicTimeDelayUntil(!document.isEmpty()).
subscribe();

格里茨 贝尔纳多

1 个答案:

答案 0 :(得分:0)

是的,有可能。

Mono有两个用于重新订阅(因此可以重新触发请求)的概念

  • retry =重新订阅上游是否已完成
  • 重复 =重新订阅上游是否成功完成

每个概念在Mono上都有针对不同用例的多个重载方法。寻找retry*repeat*方法。 例如,一个常见的用例是通过retryBackoff使用指数退避策略重试。

通过retryWhenrepeatWhen支持更复杂的用例。 reactor-extras项目包括一些构建器,可帮助您构建传递给这些方法的函数。

这里是一个示例,该示例在单声道尝试完成的情况下最多重试5次,每次尝试之间间隔5秒,重试

this.webClient
        .post()
        .uri(SERVICE_URL)
        .body(BodyInserters.fromObject(docRequest))
        .retrieve()
        .bodyToMono(Document.class)
        .retryWhen(Retry.any()
                .fixedBackoff(Duration.ofSeconds(5))
                .retryMax(5))
        .delaySubscription(Duration.ofSeconds(10))

还有其他Backoff策略(例如指数)和其他选项可用于完全自定义重试(例如,使用超时而不是最大重试次数)。

如果您需要成功重复一次,请使用.repeatWhen(Repeat...).repeatWhenEmpty(Repeat...)而不是上面的.retryWhen(Retry...)。例如:

this.webClient
        .post()
        .uri(SERVICE_URL)
        .body(BodyInserters.fromObject(docRequest))
        .retrieve()
        .bodyToMono(Document.class)
        .filter(document -> !document.isEmpty())
        .repeatWhenEmpty(Repeat.onlyIf(repeatContext -> true)
                .exponentialBackoff(Duration.ofSeconds(5), Duration.ofSeconds(10))
                .timeout(Duration.ofSeconds(30)))
        .delaySubscription(Duration.ofSeconds(10))

如果要重新订阅成功或失败,也可以将.retry*.repeat*链接在一起。