fix: release async cluster transaction connections to their real owner - #4254
fix: release async cluster transaction connections to their real owner#4254ahmed5145 wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0ef10fe0e9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
Reviewed by Cursor Bugbot for commit 0ef10fe. Configure here.
|
Hey @ahmed5145, thank you for your fast reaction on this! I'll review it later this week. Meanwhile, can you please fix the conflicts and rebase with master? |
When the slot map changes while an async TransactionStrategy holds a connection, release it to its actual ClusterNode owner before acquiring from the newly resolved node. Apply the same ownership resolution in reset() and _reinitialize_on_error() for sync/async parity (redis#4253 item 1).
0ef10fe to
8629be1
Compare
|
Thanks! Rebased onto latest master and resolved the conflict in |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8629be18d4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 16a7976064
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Hey @petyaslavova, friendly ping. Branch is updated with master. Ready for review whenever you have time. CI is nearly green (365/368). The two failures are the known flaky standalone pubsub test ( |
Mukller
left a comment
There was a problem hiding this comment.
Verified locally on the PR branch (Python 3.13) as far as possible without a live cluster:
What I checked statically and found correct:
- Owner-resolution key consistency:
find_connection_owner()buildsget_node_name(connection.host, connection.port)— exactly the formatnodes_manager.nodes_cacheis keyed by (node.name). The lookup is sound. owns_connectioncontract:ClusterNode._connectionsis appended to in the acquire path (self._connections.append(connection)), so membership testing is a valid ownership predicate;__slots__-declared, list-backed, cheap for pool-sized n.- The three release sites are now owner-correct:
_get_client_and_connection_for_transaction(stale connection after MOVED refresh → released to real owner, fresh one acquired),_reinitialize_on_error, andreset()'s finally-block. The detach-before-release discipline is preserved, and both new fallbacks (elif self._transaction_node:in reset; silent drop when no owner exists in the topology-change path) are reasonable — a connection whose node vanished from topology belongs to a pool that's being torn down anyway.
Tests: all mock-based transaction tests pass locally (-k "transaction or Transaction" → 3 passed). One new test fails locally (test_evalsha_zero_keys_in_transaction_pipeline[pool]) plus two setup errors — but those are server-dependent tests failing with ConnectionRefusedError: localhost:6379, identical to how server-dependent tests fail on upstream main in this environment; not related to the diff.
CI shows 365 green with 2-3 scattered matrix failures — same flaky-infra pattern visible on neighboring PRs today.
One residual question for maintainers (no blocker): in _get_client_and_connection_for_transaction, if the held connection's node was removed from the topology (find_connection_owner → None), the reference is dropped without release. That looks intentional (the old pool is being disposed), but it might be worth a one-line comment there so future readers don't "fix" it into a double-release.
Good catch on the stale-owner leak — this matches the sync TransactionStrategy behavior now.

When the slot map changes while an async
TransactionStrategyholds a connection, release it to its actualClusterNodeowner before acquiring from the newly resolved node. Apply the same ownership resolution inreset()and_reinitialize_on_error()for sync/async parity (#4253 item 1).Description of change
Addresses #4253 (item 1). Follow-up from the review of #4206.
Sync
TransactionStrategyalready checks pool ownership before reusing a held transaction connection and releases viafind_connection_owner. Async did not:_get_client_and_connection_for_transaction()recomputed_transaction_nodefrom the current slot map but reused_transaction_connectionunconditionally, andreset()/_reinitialize_on_error()released through_transaction_node. If another operation refreshed the sharednodes_managertopology while this pipeline held a connection duringWATCH(without this pipeline itself raisingMOVED/ASK), the next command could send on a stale connection andreset()could push that connection onto the wrong node's free queue.This PR brings async in line with sync:
ClusterNode.owns_connection()/NodesManager.find_connection_owner()_get_client_and_connection_for_transaction()reset()and_reinitialize_on_error()resolve the owner explicitly before releaseNo public API changes. Sync is unchanged (already correct). Item 2 of #4253 (sync
Script→ cluster pipelineEVALSHAcoverage) stays in #4206 and is not included here.Pull Request check-list
Note
Medium Risk
Touches async cluster connection pooling during WATCH/MULTI transactions after topology refresh. Incorrect ownership handling can leak or cross-pool connections, but the change is localized and covered by a new test.
Overview
Fixes async cluster
TransactionStrategyso a connection held across a concurrent slot-map refresh is released to its realClusterNodeinstead of being reused or returned via a stale_transaction_node.Adds
ClusterNode.owns_connection()andNodesManager.find_connection_owner()._get_client_and_connection_for_transaction()now drops the old connection when the resolved node does not own it;reset()and_reinitialize_on_error()look up the owner by host/port beforerelease().Brings async in line with sync for #4253 (item 1). No public API change. A unit test covers mid-WATCH retargeting and
reset()with a stale node pointer.Reviewed by Cursor Bugbot for commit 16a7976. Bugbot is set up for automated code reviews on this repo. Configure here.