有条件地重复或重试 Mono 与 Spring WebFlux 中的 Webclient

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

我们有一些业务休息服务服务,可以返回生成的文档。此文档的生成是从在此文档之前调用的另一个服务触发的。但是,回到业务上来:文档生成服务需要 10-30 秒。我们要做的是:在10秒后检查是否生成了文档(Mono)。如果是这样,一切都很好。如果没有,请在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

是的,这是可能的。

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

  • 重试 = 如果上游完成且出现异常,则重新订阅
  • repeat = 如果上游成功完成,则重新订阅

每个概念都有多个重载方法,用于不同的用例。查找 和 方法。例如,要在没有延迟的情况下重试最大次数,请使用 。Monoretry*repeat*retry(int numRetries)

通过 和 方法支持更复杂的用例,如以下示例所示。retryWhenrepeatWhen

重试当

如果单声道完成且出现异常,则重试,每次尝试之间最多 5 次,间隔 5 秒::

// From reactor-core >= v3.3.4.RELEASE
import reactor.util.retry.Retry;

this.webClient
        .post()
        .uri(SERVICE_URL)
        .body(BodyInserters.fromValue(docRequest))
        .retrieve()
        .bodyToMono(Document.class)
        .retryWhen(Retry.fixedDelay(5, Duration.ofSeconds(5)))
        .delaySubscription(Duration.ofSeconds(10))

重试生成器支持其他退避策略(例如指数)和其他选项,以完全自定义重试。

请注意,上面使用的方法是在 reactor-core v3.3.4.RELEASE 中添加的,并且该方法已被弃用。在 reactor-core v3.3.4.RELEASE 之前,您可以使用 reactor-extras 项目中的重试函数生成器来创建一个 to 传递给 。retryWhen(Retry)retryWhen(Function)FunctionretryWhen(Function)

重复当

如果您需要在成功时重复,请使用 或 代替上面。.repeatWhen.repeatWhenEmpty.retryWhen

使用 reactor-extras 项目中的重复函数生成器创建重复,如下所示:Function

// From reactor-extras
import reactor.retry.Repeat;

this.webClient
        .post()
        .uri(SERVICE_URL)
        .body(BodyInserters.fromValue(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))

您还可以将 a 与 a 链接,如果要在成功或失败时重新订阅。.retry*.repeat*


答案 2

推荐