如何延迟重复的WebClient获取请求

时间:2019-02-08 11:58:15

标签: spring-webflux project-reactor

我正在使用Spring 5 WebClient从REST API重复获取正在运行的进程的某些状态。

here的帮助下,我现在来到了这个解决方案:

webClient.get().uri(...).retrieve.bodyToMono(State.class)
          .repeat()
          .skipUntil(state -> stateFinished())
          .limitRequest(1)
          .subscribe(state -> {...});

尽管这可行,但get请求的触发率很高。将请求速率限制为每秒1个请求的正确方法是什么?

我尝试使用delayElements(Duration.ofSeconds(1)),但这只会延迟结果,而不会延迟请求本身。

4 个答案:

答案 0 :(得分:2)

您可以将repeatWhen运算符与伴侣Publisher的自定义实现一起使用

Mono.just("test")
        .repeatWhen(longFlux -> Flux.interval(Duration.ofSeconds(1)))
        .take(5)
        .log()
        .blockLast();

或使用reactor-addons中的Repeate功能

Mono.just("test")
        .repeatWhen(Repeat.times(Long.MAX_VALUE)
                .fixedBackoff(Duration.ofSeconds(1)))
        .take(5)
        .log()
        .blockLast();

答案 1 :(得分:0)

在您的情况下,还有另一种解决方法,您可以使用Flux作为限制器压缩每个呼叫。

library(tidyverse)
library(qdapTools)
rownames_to_column(mtcars) %>%
     mutate(rowname = word(rowname)) %>% 
     pull(rowname) %>% 
     mtabulate %>% 
     bind_cols(mtcars, .)

尽管我本以为.zipWith(Flux.interval(Duration.of(1, ChronoUnit.SECONDS))) 可以工作,但也许您没有将其放在Webclient堆栈的正确阶段。

答案 2 :(得分:0)

问题的替代解决方案

Flux.interval(Duration.ZERO, Duration.ofSeconds(1))
        .onBackpressureDrop()
        .concatMap(i -> webClientCall(...), 1)
        //or flatMap() if you want send request each second
        .filter(state -> stateFinished(state))
        .next()
        .timeout(Duration.ofSeconds(...))
        //
        .subscribe(state -> {...});

但是请记住,如果您是通过自己的方式(而不是通过Spring方式)进行订阅的,那么Reactor订阅者上下文将不会传播到您的请求(没有安全上下文,侦探等)

答案 3 :(得分:0)

您正在使用delayElements告诉我,您将其放在重复项之后。您要延迟的是对WebClient的订阅。

webClient
      .get()
      .uri(...)
      .retrieve
      .bodyToMono(State.class)
      .delaySubscription(Duration.ofSeconds(1)) //Just add this before the repeat
      .repeat()
      .skipUntil(state -> stateFinished())
      .limitRequest(1)
      .subscribe(state -> {...});

这样做可以确保在第n个请求的响应和第n + 1个请求的触发之间存在秒数。如果您需要固定的呼叫频率,而不管每个请求响应的时间如何,请按照Roman的建议用Flux.interval包装代码。