Don't leak connections in load-balanced topology#3041
Open
jamis wants to merge 2 commits intomongodb:masterfrom
Open
Don't leak connections in load-balanced topology#3041jamis wants to merge 2 commits intomongodb:masterfrom
jamis wants to merge 2 commits intomongodb:masterfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR aims to fix connection-pool slot leaks in load-balanced mode when pinned cursor/change-stream connections die before cleanup runs. It updates the cursor reaper and related cursor/change-stream handling so dead pinned connections are returned or marked appropriately instead of exhausting the pool.
Changes:
- Add error handling around pinned-connection cleanup in the cursor reaper and change stream initialization.
- Treat
ConnectionPerishedlike other getMore network failures so cursors skipkillCursorson close. - Add regression/spec coverage for cursor reaping, change stream checkout cleanup, and
ConnectionPerishedbehavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
spec/mongo/cursor_spec.rb |
Adds unit coverage for ConnectionPerished during getMore. |
spec/integration/cursor_reaping_spec.rb |
Adds load-balanced integration coverage for cursor reaper cleanup after socket death. |
spec/integration/cursor_pinning_spec.rb |
Adds regression coverage for change stream checkout cleanup on initial-query failure. |
lib/mongo/server/connection_pool.rb |
Adds a pool state helper for tests/debugging. |
lib/mongo/cursor.rb |
Marks ConnectionPerished as a getMore network error. |
lib/mongo/collection/view/change_stream.rb |
Checks out/checks in load-balanced change stream connections more defensively. |
lib/mongo/cluster/reapers/cursor_reaper.rb |
Ensures pinned connections are checked in after killCursors attempts on LB cursors. |
lib/mongo/cluster.rb |
Adds a helper to trigger the periodic executor from tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Also, #unpin will always be defined on connections that reach this point; the guard is unnecessary
comandeo-mongo
approved these changes
May 7, 2026
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.
In load-balanced topology, the MongoDB Ruby driver permanently leaks connection pool slots when a pinned connection's socket dies before the cursor reaper can clean it up.
The specific code path:
With
max_pool_size: 3and three pinned connections when the network fails, all three slots leak and every subsequent operation getsConnectionCheckOutTimeout.The fix: Wrap the
execute_with_connection+check_inpair in ``begin/rescue/ensurein cursor_reaper.rb so check_in always runs. Also callconnection.unpin(:cursor)` (guarded by `respond_to?`) so the pool's pruning logic doesn't skip the dead connection.Three companion changes are also implemented:
Error::ConnectionPerishedto the get_more rescue list so@get_more_network_erroris set on perished connections