Closed barchetta closed 1 year ago
The answer to this question depends heavily on what <doSomething>
is. I will try to answer for each option I can see:
doSomething
is non-blocking and does not add anything to memory (such as increasing a counter)doSomething
is blockingdoSomething
is non-blocking, but does add stuff to memory temporarily (such as writing to a queue, invoking a remote service)My answers:
forEach
CompletionStage
, Single
or Multi
created by the asynchronous/non-blocking task (@danielkec please provide your example) .flatMap(i -> Single.create(CompletableFuture.runAsync(() -> {
//... something long and blocking
}), true), 1, false, 1)
.ignoreElements();
We need to align on a consistent guidance to reactive streams back pressure. I've heard different takes from different people. For example:
Let's assume the result set is huge. How should this ensure there is back pressure? My understanding (which could be wrong) is two possible scenarios:
doSomething
runs its business logic synchronously. This results in back pressure because of the implementation ofJdbcStatementQuery.RowPublisher
which loops over the result set callingonNext()
on each row before getting the next.doSomething
runs asynchronously, dumping its work on a thread pool or a queue as fast as possible. This results in little to no back pressure and can lead to resource exhaustion.So, which is our guidance? Do 1 and get back pressure "for free"? Or do 2 and provide back pressure exactly how? The second option requires that the user control the rate and magnitude of
Subscription.request()
, but that is often buried in the terminal operation -- where they don't have control. Or if they want to control back pressure, must the terminal operation besubscribe()
where they do have control?This also begs the question of do we want to provide a more explicit feature for throttling? Somehow giving the user explicit control over throttling for terminal operations.
Reference: