fix(connection): snapshot Date in heartbeat handler and flush queue on recovery#16203
Merged
vkarpov15 merged 2 commits intoApr 1, 2026
Merged
Conversation
…n recovery (Automatticgh-16183) The heartbeat handler in drivers/node-mongodb-native/connection.js used the global Date.now() instead of a snapshotted copy, causing fake timers to write incorrect timestamps to _lastHeartbeatAt. Additionally, when a stale heartbeat caused readyState to report disconnected, buffered operations were never flushed because _readyState never actually changed — so no state change event fired. This extracts _flushQueue() from onOpen() and calls it from the heartbeat handler when the connection is no longer stale.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes connection staleness false-positives and ensures buffered operations resume after a stale-heartbeat “recovery”, aligning the node-mongodb-native driver connection behavior with the core Connection implementation and preventing hangs like startSession() timing out under Date-mocking test frameworks.
Changes:
- Snapshot
globalThis.Dateinlib/drivers/node-mongodb-native/connection.jsso heartbeat timestamps use the real clock even ifglobalThis.Dateis later faked. - Flush buffered connection operations from the heartbeat success handler when a previously-stale connection becomes non-stale again (including
useDb()child connections). - Extract queue-flushing into
Connection.prototype._flushQueue()and add tests covering the fixed scenarios.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
test/connection.test.js |
Adds regression tests for Date snapshotting and queue flushing on heartbeat recovery (including child dbs). |
lib/drivers/node-mongodb-native/connection.js |
Snapshots Date and flushes _queue / child queues on serverHeartbeatSucceeded when the connection is no longer stale. |
lib/connection.js |
Refactors onOpen() to call a new _flushQueue() helper method. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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
Fixes #16183. Two related bugs in the heartbeat staleness check:
Missing Date snapshot:
drivers/node-mongodb-native/connection.jsused the globalDate.now()in theserverHeartbeatSucceededhandler instead of a snapshotted copy (likelib/connection.jsalready does). When test frameworks fakeglobalThis.Date,_lastHeartbeatAtgets a fake timestamp while thereadyStategetter uses the realDate.now(), causing false staleness detection.No recovery path for buffered operations: When a stale heartbeat causes
readyStateto reportdisconnected, operations buffer into_queue. When the next heartbeat refreshes_lastHeartbeatAt,readyStatereturnsconnectedagain, but the queue is never flushed because_readyStatenever actually changed — so no state change event fires andonOpen()is never called. This extracts_flushQueue()fromonOpen()and calls it from the heartbeat handler when the connection is no longer stale.Test plan
globalThis.DateuseDb()) queues also flush on heartbeat recoveryconnection pool sharingtests all pass