In reactor, when I have a quick producer but a slow consumer, and the values in the Reactor stream is like a "snapshot", I would like the consumer to process the latest value in the stream and drop the others. (For example, a consumer that shows the exchange value in GUI vs. a producer that converts the exchange ticks to a Flux
.)
The Flux#onBackpressureLatest()
operator seems to be the right way to go.
I did some Googling and find some usage examples:
Flux.range(1, 30)
.delayElements(Duration.ofMillis(500))
.onBackpressureLatest()
.delayElements(Duration.ofMillis(3000))
.subscribe { println("got $it") }
This puts a manual delay after onBackpressureLatest()
. It's more like a Flux#sample(Duration)
rather than a slow consumer.
Internally, the delayElements(Duration)
operator wraps a concatMap
, so I converted this into:
Flux.range(1, 30)
.delayElements(Duration.ofMillis(500))
.onBackpressureLatest()
.concatMap { Mono.just(it).subscribeOn(Schedulers.boundedElastic()) }
.subscribe { item ->
println("got $item")
// simulate slow subscriber with sleep
Thread.sleep(3000)
}
This is like the answers provided in question Latest overflow strategy with size 1 or any alternatives. However, it looks a bit wired. I don't understand why we need the concatMap(op)
or flatMap(op, 1, 1)
call to get the onBackpressureLatest()
working.
I tried the following (simplified) versions but they do not work as expected, why?
// not working try - 1
Flux.range(1, 30)
.delayElements(Duration.ofMillis(500))
.onBackpressureLatest()
.publishOn(Schedulers.boundedElastic())
.subscribe { item ->
println("got $item")
// simulate slow subscriber with sleep
Thread.sleep(3000)
}
// not working try - 2
Flux.range(1, 30)
.delayElements(Duration.ofMillis(500))
.onBackpressureLatest()
.publishOn(Schedulers.boundedElastic())
.subscribe(object : BaseSubscriber<Int>() {
override fun hookOnSubscribe(subscription: Subscription) {
// explicitly request 1
subscription.request(1)
}
override fun hookOnNext(value: Int) {
// simulate slow subscriber with sleep
Thread.sleep(3000)
println("got $value")
// explicitly request 1
request(1)
}
})