Skip to content

Share an observe multiplexer while its driver starts - #14

Draft
mark1russell7 wants to merge 1 commit into
develfrom
fix/observe-changes-sharing
Draft

mark1russell7 wants to merge 1 commit into
develfrom
fix/observe-changes-sharing

Conversation

@mark1russell7

Copy link
Copy Markdown

Summary

_observeChanges shares one ObserveMultiplexer per cursor, but registers a new one in _observeMultiplexers only after its driver has started (_selectReactivityDriver, then _init):

  • Duplicate observers. observeChanges calls for the same cursor that arrive while the first driver starts each create their own multiplexer and driver, and run the first query again. The last one to start keeps the map entry.
  • A live multiplexer drops out of the map. onStop deletes the map entry without a check. When an earlier multiplexer stops, it removes the entry of a live one, and later calls start yet another.

A related gap: queryError stops the multiplexer but never settles its ready promise, so handles already waiting on it wait for good. The polling driver hits this today, because its first poll runs after _init returns, when later calls can already share the multiplexer.

Changes

  • mongo_connection.js: the multiplexer is registered before anything yields, and onStop removes the entry only if it is still this multiplexer. A driver that fails to select, construct or _init goes to queryError.
  • observe_multiplex.ts: queryError rejects the ready promise, so every waiting handle gets the error. A handle that found the multiplexer before it stopped gets the same error, instead of a TypeError on the null _handles. A second queryError for the same multiplexer only rethrows, because a driver can report its first query's error and then throw it from _init.
  • New server tests in tests/observe_sharing_tests.js.

Verification

The mongo package's server tests (test-server-tests-in-console-once), run twice:

  • With the fix reverted: the 3 new tests fail, and the other 231 pass. The two sharing tests see two different multiplexers. The queryError test times out, because the waiting handles never settle.
  • With the fix: 234 of 234 pass.

_observeChanges registered a new multiplexer in _observeMultiplexers
only after its driver had started. observeChanges calls for the same
cursor that arrived meanwhile each created their own multiplexer and
driver, and ran the first query again. The last one to start kept the
map entry. onStop deleted the entry without a check, so when an earlier
multiplexer stopped, it removed the entry of a live one, and later calls
started yet another.

The multiplexer is now registered before anything yields, and onStop
removes the entry only if it is still this multiplexer.

A driver that fails to start now goes to queryError, which removes the
multiplexer. queryError now also rejects the ready promise, so every
handle waiting on the multiplexer gets the error, and a handle that
found the multiplexer before it stopped gets it too. Before, those
handles waited for good. The polling driver already left handles in
that state, because its first poll runs after _init returns.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant