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
Monitor command #1033
Monitor command #1033
Conversation
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.
LGTM. @RoeyPrat question: does it make sense to have a close()/exit thing here to release the connection?
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's no connection cleanup or flow control here. Presumably someone isn't going to monitor all commands forever. There should be some way for a user to say "OK, I'm done monitoring." Such a method would likely call
self.connection.disconnect
and returnself.connection
to theconnection_pool
. Other parts of the library have areset()
method that does this. -
Is there a benefit in separating the Monitor object init from sending the MONITOR command? What's the reasoning that I have to start this by calling
client.monitor().monitor()
rather than justclient.monitor()
? -
This might be a great use case for a context manager. The connection can be cleaned up automatically in
__exit__
. Maybe something like this:
with client.monitor() as m:
for command in m.listen():
...
if <some behavior indicates that we want to stop>:
m.stop() # maybe this trips a flag that controls the while loop in listen()
-
The unit tests need to be written in py.test format like the rest of the test suite. Your tests weren't run and I suspect that if they did, they'd fail, because...
-
In
parse_response()
you're comparing a potential bytes response to a string. That will fail in Python 3 unlessdecode_responses=True
. Instead, use thebool_ok
response handler (you can invoke it directly) to get a boolean. -
Also in
parse_response()
you're splitting a potential bytes string (the command) with a string (' '
). That will fail in Python 3 unlessdecode_responses=True
. We should split the command on' '
orb(' ')
depending on the value ofdecode_responses
. -
Should we also parse out the client section (
[0 127.0.0.1:47832]
) of the response into a separate field in the dict returned to the user? -
It might also be nice to have another field in the response called
command_name
. This would always be a native string that's the command name that was executed, e.g., 'ZADD' or 'CONFIG GET'. Note that this could be two words. If we did this, it shouldn't remove the command name from thecommand
field. I don't see this as critical and am happy to merge without this. But it could be quite nice for a user.
@andymccurdy I changed monitor to use context manager. also, the message is parsed. |
redis/client.py
Outdated
|
||
def __enter__(self): | ||
self.connection.send_command('MONITOR') | ||
assert self.next_command() |
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'd suggest reading the response off the connection and checking it with bool_ok
here rather than at the top of next_command
.
If the response is not OK, I think we should raise a RedisError
(or a subclass) rather than an AssertionError
.
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.
ok. I'm setting error to RedisError('MONITOR failed: %s' % response)
# This part with the OK is only needed when we connect initially. | ||
if bool_ok(response): | ||
return True | ||
command_time, command_data = response.split(' ', 1) |
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.
This is going to fail on Python3 with decode_responses=False
. I'm looking at another solution for this now...
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.
for now, I'm setting "If decode_responses=False, return monitor output without parsing".
I still need to create tests for this feature... |
@RoeyPrat I took a look at this a bit yesterday and found some issues.
|
@RoeyPrat I took your PR and made some changes attempting to fix the problems I outlined above. The branch is here: https://github.com/andymccurdy/redis-py/tree/monitor I think everything works as expected with this. Can you review and let me know what you think? Thanks! |
@andymccurdy - looks great! I see no problem in your branch. |
Merged. Thanks @RoeyPrat |
This is a rebase of #194 by @dougk7.
He implemented the MONITOR command in a similar way to PubSub, using a generator to get the messages.
I also fixed some PEP8 and formatting issues and added the command to README.
This issue was also mentioned in #805.
Thanks!