-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Race condition in handling health checks for pub-sub #1720
Comments
Hey, In the posted example we see the following flow:
Therefore, we shouldn't use self.channels and self.patterns to determine whether a health check needs to be executed, but we should have another variable to indicate whether this is the first command execution, and if so, to run a health check. However, a poller thread may be started before subscribing to a channel, e.g. :
In this case, the health check will be performed and we will still get a race reading from the socket with the poller thread.
|
Isn't there still a race between the the main thread checking the flag when issuing the first command, and the poller thread clearing the flag in |
Version: What redis-py and what redis version is the issue happening on?
redis-py 4.0.0, redis 6.2.6 (have also reproduced a failure in redis-py 3.5.3, although with a different failure mode)
Platform: What platform / version? (For example Python 3.5.1 on Windows 7 / Ubuntu 15.10 / Azure)
Python 3.8, Ubuntu 20.04
Description:
PubSub.execute_command
checksself.subscribed
before deciding whether to issue a health check, but if we've issued an unsubscribe to the last channel but not yet received the unsubscribe confirmation to the server,self.subscribed
will still be true. The response to that (a string "PONG") can then be misinterpreted as a pub-sub response. This shows up asget_message
returning{'type': 80, 'pattern': None, 'channel': 79, 'data': 78}
, where 80, 79, 78 are the ASCII codes of P, O, N (they're integers because indexing abytes
gives integers).With redis-py 3.5.3 I think I hit the opposite problem, where a 'PING redis-py-health-check' is issued thinking that the connection has subscriptions, and expecting a multi-bulk response ["ping", "redis-py-health-check"], but getting just "redis-py-health-check" back on the wire because there are no subscriptions. I think I once saw the same thing happen with redis-py 4.0.0, but I've been unable to reproduce it since and I have been jumping between the versions to compare, so I may be mistaken.
Here is some minimal code that illustrates the issue. It doesn't reliably reproduce it - I have to run it in a loop and can take 5-20 times to reproduce. When it does, it prints the following. I haven't dug into the backtrace and it might be just something in my own code - it's the message with numbers in the fields that is the smoking gun.
I think both cases can be dealt with by ignoring responses that are a single string instead of a multi-bulk when trying to parse a pubsub message, although it is a bit hacky.
Output:
The text was updated successfully, but these errors were encountered: