-
Couldn't load subscription status.
- Fork 89
bugfix: reading from a silent stream should not fail with RedisCommandTimeoutException
#952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bugfix: reading from a silent stream should not fail with RedisCommandTimeoutException
#952
Conversation
…ndTimeoutException` If the stream has no data for a long time, lettuce will throw `RedisCommandTimeoutException`. In that case we don't want to fail the stream and we should restart the read.
RedisCommndTimeoutExceptionRedisCommandTimeoutException
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TY
|
@arturaz I think I was a bit too hasty, I have had more time to look at this in detail.
If block was not used , then a timeout exception occurred most likely due to underlying network latency issues (as you can see from the myriad of issues raised here In that case perhaps this should be viewed as a feature and require opt in by the user I would also expect in the test scenario added, where one explicitly sets a timeout in the client options, the stream would be shutdown in that case. |
My case uses default option, which is I will take a look at rewriting this using the reactive redis API instead of async one to see if that helps. |
|
I migrated streaming to reactive Lettuce API, which, unfortunately, still raises the timeout exception if the stream is silent. However, I still think it's a better option than repeatedly polling using async API. The simple use case (without restarts) is very straightforward now. I also added |
|
Putting aside the switch to the Reactive API, as you are correct , as noted , it wont solve this problem.
Using the default configs for a client would result in having a CommandTimeout set to 60 seconds as its inherited by default from the connection config which has a default of 60 seconds The command timeout mechanism is ignorant of the api choice (sync/async/reactive) and will timeout regardless . See this for discussion around CommandTimeout for blocking commands In fact in the history of Redis4Cats , there is discussion if this was a wise decision to set block to 0 as default. |
|
So is there a problem with the added feature? |
|
@arturaz apologies for the delay. |
Why? The reactive API is better suited to this scenario, rather than polling Redis via the async API and maintaining queues. More over, I think the whole design of streaming API is broken due to use of the same |
|
I would like to dicsuss pros/cons of reactive an addition to the other issue you mentioned, I just think it should be a separate discussion and PR from this bug/ux fix, as it really is unrelated, and will be better served that way. |
|
OK, we can move reactivity to another PR, but can we please first discuss #963 as this is a dealbraker for otel4s-redis4cats integration? |
|
yes, I'll give it a review. TY |
|
I removed the reactivity. Turns out, when converting push-based Publisher to pull-based Stream, you can't really do any buffering, so you have to have a chunk size of 1, which is ineffective, thus the current approach is better. I left the (failed) attempt with the comment in https://github.com/arturaz/redis4cats/commit/484a28de18982d7396a80aafde91c8301d804f23 |
…s-timeout-exception
…m with simple strings.
|
Looks good. |
|
Yes. In theory this could be not breaking bincompat, but that means adding an overload with no default values (due to Scala's limitation of two methods with default values unable to share the same name), which is... weird? Can you review these PR's and give me LGTM, so I could prepare the joint version for you to review? On my local build there was a couple of minor merge conflicts. |
|
Also, what do you think of having a default |
|
Argh... The same problem surfaces in |
|
That's weird. They kind of do not, but in my codebase I had this: The error message is kind of useless. Thus I have added |
yes , I think we should . Otherwise it requires a user to be exposed to the inner workings of Lettuce and understand what CommandTimeout is. |
| block: Option[Duration] = Some(Duration.Zero), | ||
| count: Option[Long] = None, | ||
| restartOnTimeout: Option[FiniteDuration => Boolean] = None | ||
| restartOnTimeout: RestartOnTimeout = RestartOnTimeout.never |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be .always .
Keep in mind a RedisCommandTimeoutException is unrelated to network issues, rather its simpoly how long a command takes to run. When running a blocking command that waits for data, it will wait until there is data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I think it is related to network issues. If the network goes dark without any traffic on the line, you can hang there indefinitely, IIRC. Timeouts resolve that situation.
Maybe we should not provide a default here at all and force the user to choose an option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is another exception that is thrown for connection issues. This exception is not about network issues
This either needs to be on all of the operations, or none of them. Users of the library can add a similar thing themselves.
|
I have changed the default and removed |
…s-timeout-exception
|
Go for it |
If the stream has no data for a long time, lettuce will throw
RedisCommandTimeoutException.In that case we don't want to fail the stream and we should restart the read.
Alternatively we should use the lettuce reactive API, but that requires quite a large of a refactoring.