You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Given the following toy example, and especially when converting it to real code, it is very hard to control how much Reactor buffers.
In practice, it would gladly buffer many 100K of elements, when only 800 will be sufficient for an efficient flow. Looks like the only way to control this is through limitRate(). However, using it is a whack-a-mole solution, which does not translate at all from the toy example to real code.
By "buffer" I mean the count of elements that went into a pipeline and their processing is still pending, not to be confused with purposefully buffering, such as .buffer() or .cache() etc.
Reactor make good use of memory for optimal buffering before/at operators and does not store too many elements in the pipeline.
The developer should be getting close to optimal behavior out of the box or should be able to easily control the behavior to be optimal, without whack-a-mole or investing too much time to research it.
Actual Behavior
Reactor gladly buffers many 100Ks of elements, where it could easily used only 800 could have been buffered instead,
Not only that, if too much is buffered, this can have additional implication, such as drain time if takeWhile() is used, or the number of elements that will require reprocessing when a task is rerun, because the previous iteration was too greedy.
I'd claim that limitRate() is not sufficient and that tuning the pipeline to do the right thing is too difficult and, even if I invested the time to get it right, it is fragile and can easily be broken when changing the pipeline.
Worse, even the toy example below behaves differently than my real code, since the limitRate() solution did not copy the behavior, leaving me puzzled at what's going on.
Steps to Reproduce
Important notes:
limitRate(2) looks like it is ignored, but gets buffering of 7000 to 9000 items on my machine with this test (which is close to reasonable BUT, see next bullet).
Unfortunately, the use of limitRate() as per below does not copy the behavior to my real code, which still happily cache 100Ks of elements, even though both pipelines are very similar.
What happens with this is that generate() is called too eagerly while step C processes items slowly.
I am guessing that the watermark level for generate is 7.5 out of 10, but the level drops too quickly below the watermark.
Hey, thanks for bringing this up. I didn't find the time to investigate deeply and can't make any prediction as to when I can do so, but I remembered potentially related discussions that might clarify things around this subject:
Given the following toy example, and especially when converting it to real code, it is very hard to control how much Reactor buffers.
In practice, it would gladly buffer many 100K of elements, when only 800 will be sufficient for an efficient flow. Looks like the only way to control this is through
limitRate()
. However, using it is a whack-a-mole solution, which does not translate at all from the toy example to real code.By "buffer" I mean the count of elements that went into a pipeline and their processing is still pending, not to be confused with purposefully buffering, such as
.buffer()
or.cache()
etc.Note I have posted this stackoverflow question, but there were no takers.
Expected Behavior
Reactor make good use of memory for optimal buffering before/at operators and does not store too many elements in the pipeline.
The developer should be getting close to optimal behavior out of the box or should be able to easily control the behavior to be optimal, without whack-a-mole or investing too much time to research it.
Actual Behavior
Reactor gladly buffers many 100Ks of elements, where it could easily used only 800 could have been buffered instead,
Not only that, if too much is buffered, this can have additional implication, such as drain time if
takeWhile()
is used, or the number of elements that will require reprocessing when a task is rerun, because the previous iteration was too greedy.I'd claim that
limitRate()
is not sufficient and that tuning the pipeline to do the right thing is too difficult and, even if I invested the time to get it right, it is fragile and can easily be broken when changing the pipeline.Worse, even the toy example below behaves differently than my real code, since the
limitRate()
solution did not copy the behavior, leaving me puzzled at what's going on.Steps to Reproduce
Important notes:
limitRate(2)
looks like it is ignored, but gets buffering of 7000 to 9000 items on my machine with this test (which is close to reasonable BUT, see next bullet).limitRate()
as per below does not copy the behavior to my real code, which still happily cache 100Ks of elements, even though both pipelines are very similar.What happens with this is that
generate()
is called too eagerly while step C processes items slowly.I am guessing that the watermark level for generate is 7.5 out of 10, but the level drops too quickly below the watermark.
Things to try:
limitRate()
callsYour Environment
netty
, ...):java -version
): JDK 21uname -a
): WSL2 / Ubuntu 5.15.146.1-microsoft-standard-WSL2The text was updated successfully, but these errors were encountered: