-
Notifications
You must be signed in to change notification settings - Fork 2.7k
fix(asyncio): fully disconnect removed cluster nodes in NodesManager.set_nodes #4207
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?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1930,16 +1930,11 @@ def set_nodes( | |
| for name in list(old.keys()): | ||
| if name not in new: | ||
| # Node is removed from cache before disconnect starts, | ||
| # so it won't be found in lookups during disconnect | ||
| # Mark active connections so in-flight commands can | ||
| # finish, then disconnect them when their current | ||
| # operation completes. Free connections can be | ||
| # disconnected immediately. | ||
| # so it won't be found in lookups during disconnect. | ||
| # We fully disconnect the node so that all its connections | ||
| # (in-use and free) are closed immediately, preventing leaks. | ||
| removed_node = old.pop(name) | ||
| removed_node.update_active_connections_for_reconnect() | ||
| task = asyncio.create_task( | ||
| removed_node.disconnect_free_connections() | ||
| ) | ||
| task = asyncio.create_task(removed_node.disconnect()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ClusterNode.disconnect() gathers with return_exceptions=True and then re-raises the first exception, unlike disconnect_free_connections() which swallowed them. Since this is a fire-and-forget task whose only done_callback is discard, a node that goes away mid-topology-change (socket close raising) now turns into an unretrieved "Task exception was never retrieved" on the loop instead of a quiet cleanup. Probably worth wrapping the create_task target in a small helper that logs instead of raising. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unhandled exception in fire-and-forget disconnect taskMedium Severity
Reviewed by Cursor Bugbot for commit 1b92aa9. Configure here.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ClusterNode.disconnect() re-raises the first exception out of its gather, disconnect_free_connections() swallowed them (return_exceptions=True, no re-raise). This is a bare create_task whose only done_callback is the set discard, so nothing ever retrieves the result — a socket that errors on close now surfaces as "Task exception was never retrieved" on the loop instead of being ignored like before. Probably want to wrap it in a coroutine that logs and drops. |
||
| self._background_tasks.add(task) | ||
| task.add_done_callback(self._background_tasks.discard) | ||
|
Comment on lines
+1937
to
1939
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If any connection's Useful? React with 👍 / 👎. |
||
|
|
||
|
|
||


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.
When a topology refresh removes a node after a mutating command has been sent but before its response is read, this immediate disconnect makes the command raise
ConnectionError;RedisCluster.execute_command()then retries it on the refreshed topology by default. If the server already applied a command such asINCRorLPUSH, the retry applies it again and silently duplicates the write. Removed nodes should reject new work while marking active connections for disconnection only after their current operation completes.AGENTS.md reference: AGENTS.md:L158-L162
Useful? React with 👍 / 👎.