我正在使用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))
,但这只会延迟结果,而不会延迟请求本身。
答案 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
包装代码。