Fix async RedisCluster lifecycle after aclose#4069
Open
seplease wants to merge 3 commits into
Open
Conversation
|
Hi, I’m Jit, a friendly security platform designed to help developers build secure applications from day zero with an MVS (Minimal viable security) mindset. In case there are security findings, they will be communicated to you as a comment inside the PR. Hope you’ll enjoy using Jit. Questions? Comments? Want to learn more? Get in touch with us. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Reviewed by Cursor Bugbot for commit b922022. Configure here.
Collaborator
|
Hi @seplease, thank you for your contribution! I will have a look at it. |
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.

Summary
Fix async
RedisClusterreopening itself afteraclose().Previously, calling
await client.aclose()did not fully terminate the cluster client lifecycle. A later command could trigger lazy reinitialization and recreate cluster connections.This change separates "not initialized yet" from "explicitly closed" and prevents closed async cluster clients from being reused.
Fixes #3846.
Background
RedisClusteruses lazy initialization internally.The problem was that
_initializerepresented two different states at once:aclose()disconnected node connections, but also reset_initialize=True.As a result, a later command path treated the client as uninitialized and called
initialize()again, reopening cluster connections after close.That behavior made
aclose()act more like a soft reset than a terminal lifecycle operation.There was also a race window between
initialize()andaclose()where connections created during initialization could survive the close path.Changes
Introduced an explicit
_closedstate for the async cluster client lifecycle.Main changes:
_closedlifecycle tracking_ensure_open()checks before initialization and command executionaclose()to mark the client closed and prevent reuseaclose()wait for in-flight initialization before disconnecting nodesInternal cleanup paths are now split into:
aclose()_close_nodes()_disconnect_nodes()Cluster recovery paths (
MOVED,ClusterDownError,SlotNotCoveredError, and pipeline retry) now use_close_nodes()so topology refresh behavior remains unchanged.Tests
Added regression coverage for:
aclose()aclose()before initializationinitialize()/aclose()executionAlso added an integration-style regression test against a real Docker Redis Cluster.
Ran:
.venv/bin/python -m pytest tests/test_asyncio/test_cluster.py -q \ --redis-url=redis://localhost:16379/0 \ --redis-ssl-url=rediss://localhost:27379/0 \ -m 'not onlynoncluster and not redismod and not fixed_client'Result:
Also validated with:
Notes
This PR only changes the async cluster client lifecycle behavior.
The sync
RedisClusterimplementation is unchanged.Note
Medium Risk
Changes async
RedisClusterlifecycle semantics by makingaclose()terminal and adding new close/retry paths; this could break callers/tests that previously relied on implicit reinitialization after close or on specific retry behavior under cluster errors.Overview
Fixes async
RedisClusterreopening itself afteraclose()by introducing an explicit_closedstate and enforcing it via_ensure_open()checks ininitialize(),execute_command(), and pipeline/transaction execution paths.Splits connection teardown into
_disconnect_nodes()(actual disconnect),_close_nodes()(soft reset to allow topology refresh retries), andaclose()(terminal close that waits on the client lock), and updates cluster recovery/retry paths (e.g.MOVED,ClusterDownError, pipeline retries) to use_close_nodes()instead of fully closing the client.Updates async test fixtures to handle flushing a closed cluster client by creating a temporary cleanup client, and adds regression tests covering closed-client command rejection, concurrent
initialize()/aclose()behavior, init-failure cleanup, and pipeline execution after close.Reviewed by Cursor Bugbot for commit b922022. Bugbot is set up for automated code reviews on this repo. Configure here.