-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Add Redis readiness verification (#3555) #3596
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
base: master
Are you sure you want to change the base?
Add Redis readiness verification (#3555) #3596
Conversation
Hi @ManelCoutinhoSensei, thank you for your contribution! We’ll review your change soon. |
@petyaslavova you need to rerun the failed tests due to the test suit flakiness |
Hi @petyaslavova , any news about this one? |
Hi @ManelCoutinhoSensei, I have started the review, but couldn't complete it. |
Should I solve the conflicts because the PR reviews are going to be done this week or should I postpone it? |
Hi @ManelCoutinhoSensei, please wait for a while with the conflict solving. We first need to address one more planned change related to the async cluster, and then I will be able to progress on this PR. |
Hey @petyaslavova! 🙌 Just checking in to see if there are any updates or an estimated timeline for moving forward with this PR. Totally understand things can get busy — just wanted to make sure it’s still on your radar. |
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.
Hi @ManelCoutinhoSensei,
Apologies for the delay in reviewing the PR. I've added some comments and suggestions for changes that I believe will help make the code more maintainable in the long term. While the comments are placed in the sync client/connection code, they apply to the async parts as well.
redis/connection.py
Outdated
# Doing handshake since connect and send operations work even when Redis is not ready | ||
if self.check_ready: | ||
try: | ||
ping_parts = self._command_packer.pack("PING") |
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 it would be better to replace this block with a call to self._send_ping()
, and refactor that method to accept an additional argument—something like accept_no_auth_response=False
by default. This way, you can reuse the existing logic without duplicating the socket write/read operations, making the code cleaner and easier to maintain.
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 understand the desired but in order to use the read_response
part of the _send_ping
, the parsers should already be initialized (which only happens on on_connect_check_health
that is called after the _connect_check_server_ready
).
Either way I refactored the _connection
method so that i could use the send_command
command part, let me know if this suffices or if we should consider refactoring the connection flow to accommodate an earlier parser initialization
96db4ac
to
393563a
Compare
3ee1832
to
416f18f
Compare
f63c426
to
6a0f88b
Compare
50c8dbd
to
1e5241a
Compare
Hey @petyaslavova, just updated this PR after the merge of #3601 |
Hey @petyaslavova, have you had the chance of reviewing the changes you asked? |
Hi @ManelCoutinhoSensei, I was in vacation for a while and I didn't have a chance to look at this. I'm trying to catch up with the PRs this and next week. |
1e5241a
to
119ec97
Compare
Hey @petyaslavova, I updated it and it is passing all the tests on my side |
Hi @ManelCoutinhoSensei, there are some details in this PR that can't be merged into the current master state - there is a new functionality in the client that handles specific push notifications, which can be received with the command responses. If you read directly from the socket, you won't be able to use the automatic handling of those messages, which happens in the parser. |
Hey @petyaslavova,
does this comment from July 1st address what you are asking? Or is it no longer up to date? |
I have to admit I’d forgotten about this one, but yes — this is exactly the right solution here. |
Which part is the right solution? Are you saying that using the |
The parser is initialized in the init method when resp3 is used - https://github.com/redis/redis-py/blob/8403ddcfcf16c95baab330076b4905483e44fbb7/redis/connection.py#L429C25-L429C37 |
I might be wrong but even when using resp3, the parser is only initialized (meaning only the |
You’re absolutely right. 🙂 I finally had time to carefully review (and debug) the code related to the reported issue and this PR. My conclusion is that this change would introduce additional complexity without fully resolving the core problem. With the current approach, we’d force a PING on all connections, even though we already have health checks available. When health checks are enabled, a PING is executed just before the first real command as part of the initial client setup. In my opinion, the correct solution is to move the initial health-check logic (executed after the socket connect) into the retry block. That way, we can retry the entire connection-establishment flow—not just the socket connect. Something like the following will handle the retry of the whole connection establishment logic: @ManelCoutinhoSensei, what do you think about this change in direction? |
119ec97
to
5218c48
Compare
Hey @petyaslavova, Thanks a lot for taking a close look at this issue! 🙏 The problem that I originally flagged still exists ( What I was proposing was essentially the current approach (sending a Authenticated requestsIf you look at the authentication-related code (650-652, 661 and 670) we're hardcoding That would require setting def _send_ping(self):
"""Send PING, expect PONG in return"""
self.send_command("PING", check_health=False)
try:
if str_if_bytes(self.read_response(disconnect_on_error=False)) != "PONG":
raise ConnectionError("Bad response from PING health check")
except AuthenticationError:
# That's fine -> server is healthy
# Reset _parser due to the rewind on error mechanic that would make it read the same answer twice
# The rational behind rewind on error when disconnect_on_error is deactivated should be rethought perhaps
self._parser.on_disconnect()
self._parser.on_connect(self) Let me know what you think! 😊 |
aeb774e
to
29b969f
Compare
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.
❌ The following Jit checks failed to run:
- secret-detection-trufflehog
- static-code-analysis-semgrep-pro
#jit_bypass_commit
in this PR to bypass, Jit Admin privileges required.
More info in the Jit platform.
Hi again @petyaslavova 👋, I’ve been experimenting with this other issue (better explained in this comment) and realized that my previous explanation wasn’t entirely accurate. Here’s the situation:
This was something I didn’t account for in my previous comment. To address this, I updated the synchronous version with a proposal where the I’ve also removed the previous flag since, as mentioned earlier, the library’s default behavior already includes sending this On top of that, this approach also resolves the #3203 (mentioned before) - at least in the way I’ve been reproducing it. Eager to hear your thoughts! Should we move forward with this solution and implement it for the async version as well? 🚀 |
29b969f
to
0548e64
Compare
0548e64
to
92db1fe
Compare
Pull Request check-list
Please make sure to review and check all of these items:
NOTE: these things are not required to open a PR and can be done
afterwards / while the PR is open.
Description of change
Fixes #3555 (specially the comment on that issue)
Please check if you'd rather run the tests with
check_ready=True
by default (I also tested that) and if you think that any other tests deserve a second version with this flag set.