runtime: retry Redis operations against the current client - #1620
Open
nabrahma wants to merge 1 commit into
Open
runtime: retry Redis operations against the current client#1620nabrahma wants to merge 1 commit into
nabrahma wants to merge 1 commit into
Conversation
Contributor
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
keys and scan_keys passed self._client.keys and self._client.scan into _execute_with_retry. Python resolves those attributes at the call site, so the bound method addressed whichever client object existed before the retry loop ran. On a ConnectionError the loop clears _connected and reconnects, and connect assigns a new redis.Redis to self._client, but the retry still invoked the old bound method. Every attempt went back to the connection that had already failed, and both methods then returned an empty list rather than raising, which a caller cannot tell apart from no keys matching. Resolve self._client inside a lambda so each attempt addresses the current client. This also makes the _ensure_connected call in the loop effective: self._client.scan previously raised AttributeError when the client was None, either before the first connect or after _cleanup_connection. Adds tests for the module, which had none. Signed-off-by: Nabaskar Brahma <nabaskarforcode99@gmail.com>
nabrahma
force-pushed
the
fix/redis-retry-current-client
branch
from
August 14, 2026 14:20
177c06f to
f0e6d73
Compare
This was referenced Aug 15, 2026
Contributor
Author
|
@LiZhenCheng9527 PTAL! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What type of PR is this?
/kind bug
What this PR does / why we need it:
keys()andscan_keys()passedself._client.keysandself._client.scaninto_execute_with_retry. Python resolves those attributes at the call site, so the bound method addressed whichever client object existed before the retry loop ran. On aConnectionErrorthe loop clears_connectedand reconnects, andconnect()assigns a newredis.Redistoself._client, but the retry kept invoking the old bound method. Every attempt went back to the connection that had already failed, and both methods then returned an empty list rather than raising, which a caller cannot tell apart from no keys matching.Resolving
self._clientinside a lambda makes each attempt address the current client. It also makes the_ensure_connectedcall inside the loop effective, sinceself._client.scanpreviously raisedAttributeErrorwhen the client wasNone, either before the firstconnect()or after_cleanup_connection().Driving the real
RedisClientwith a fake whose client object is replaced on eachconnect(), counting calls per client generation:Generation 0 is the dead client. Before, it absorbed all four attempts and the reconnected clients were never called.
Adds
python/kthena/tests/test_redis_client.py, which had no tests. All five cases fail on main and pass here.Which issue(s) this PR fixes:
Fixes #1618
Special notes for your reviewer:
Scoped to the callable change only. @aeron-gh suggested keeping the connection pool cleanup separate, and that is the right call for a second reason: doing it as
_cleanup_connection()inside_execute_with_retryintroduces a race.connect()is guarded by_connection_lockand_cleanup_connection()is not, so with two concurrent operations one coroutine's cleanup can disconnect the pool the other just established. I have a failing test for that, so the pool fix wants to live insideconnect()under the lock, in its own PR.Does this PR introduce a user-facing change?