You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: remove cosmosDbMode test flag, simplify Cosmos DB detection
Remove the cosmosDbMode / isRealCosmosDb split. isCosmosDb is now set
only by server detection (hello.internal.cosmos_versions), never by a
test flag.
The sentinel approach is a single code path that works on both:
The sentinel logic itself is identical on MongoDB and Cosmos DB:
write a checkpoint document ({$inc: {i: 1}}), wait for it in the
change stream, match by documentKey._id and fullDocument.i, use
the event timestamp as the LSN, commit. This passes on both.
The branching between MongoDB and Cosmos DB is minimal and
environmental, not architectural:
- Which stream to open (client.watch vs db.watch)
- Which timestamp to use (wallTime vs clusterTime)
- Whether to initialize the stream before checkpointing
- Whether startAtOperationTime is available
These are server-level differences, not sentinel-level. The sentinel
matching, the checkpoint resolution chain, and batch.commit are the
same code on both backends.
Why cosmosDbMode on standard MongoDB does not work:
The test flag tried to force the Cosmos DB code path on standard
MongoDB. The problems were all about mixing two environments, not
about the sentinel approach:
1. Lazy ChangeStream initialization. The MongoDB driver's ChangeStream
is lazy — the aggregate command is not sent until the first
tryNext()/hasNext() call. On standard MongoDB, startAtOperationTime
sets the stream's start position explicitly, so events committed
before the first tryNext() are included. On Cosmos DB (no
startAtOperationTime), the stream starts from "now" — whenever the
first tryNext() runs. This requires opening the stream and forcing
initialization BEFORE creating checkpoint documents, reversing the
order used on standard MongoDB.
2. Wall-clock LSN precision. Cosmos DB events use wallTime (second
precision, increment 0) instead of clusterTime (sub-second, real
increment). When cosmosDbMode forces wallTime on standard MongoDB,
the createCheckpoint function still has access to operationTime
(which has real increments). Mixing the two clock sources causes
LSN comparisons to fail when timestamps fall in the same second:
wallTime produces increment 0, operationTime produces increment N,
and 0 < N means the checkpoint never resolves.
3. Sentinel checkpoint matching. The sentinel flow depends on the
stream being initialized before the marker is written. Combined
with issue 1, this creates a deadlock on standard MongoDB where
tryNext() blocks waiting for events that have not been created yet.
These issues compound: fixing one exposes the next. A test flag that
partially simulates Cosmos DB creates more problems than it solves
because the underlying assumptions about stream initialization and
clock sources are fundamentally different between the two servers.
Changes:
- Remove cosmosDbMode from ChangeStreamOptions
- Remove isRealCosmosDb field — isCosmosDb is the only flag
- createCheckpoint auto-detects via session.operationTime == null
- Integration tests skip unless COSMOS_DB_TEST=true
- Unskip write checkpoint test (works against real Cosmos DB)
- Fix write checkpoint assertion (returns object, not bigint)
- Revert getClientCheckpoint to simple cp.lsn >= lsn comparison
Remaining test failures against Cosmos DB (3/26):
resume after restart — PSYNC_S1346 Error reading MongoDB ChangeStream
The resume test stops streaming, creates a new context, loads active
sync rules, and starts streaming again from the stored resume token.
On Cosmos DB this fails with a change stream error. Likely causes:
- Cosmos DB resume tokens may expire faster than MongoDB (400MB
change stream log limit vs time-based oplog retention)
- The token format (base64 vs hex) may not round-trip correctly
through MongoLSN serialization/deserialization
- Cosmos DB may not support resumeAfter with tokens from a previous
connection
Needs separate investigation of the resume token persistence path
in MongoLSN.fromSerialized().
0 commit comments