A change stream can resume after a disconnect when its token is retained; the consumer must still handle replay and token expiry.
Spring Data MongoDB change stream: resume token and idempotent projection
The token is a recovery cursor
A product-search projector watches a MongoDB collection and updates a search index. After processing one event, it stores the event's resume token along with projector progress. On restart it resumes from that token rather than starting at the current time and silently skipping an outage window. Change streams require a replica set or sharded cluster. A timestamp is a weaker recovery cursor when events share a time boundary.
Make replay harmless
Persisting the search update and the MongoDB resume token in different systems cannot be one ordinary database transaction. A crash between them can replay the event. Use document ID plus source version as an idempotency key, and let the target reject older versions. Reconnect snapshots solve a related gap for browsers; dead-letter handling covers poison events after repeated failure.
Drill the outage
Stop the projector, write several source versions, restart from the saved token, and verify the final target version. Then force an expired or invalid token and define a full-rebuild path instead of pretending the stream continued. The code names the resume API; token persistence, lease ownership and target writes are separate application responsibilities.
Implementation sketch
ChangeStreamOptions options = ChangeStreamOptions.builder()
.resumeAfter(savedResumeToken)
.build();
Flux<ChangeStreamEvent<ParcelAllocation>> events =
reactiveMongoTemplate.changeStream(
"parcel_allocations", options, ParcelAllocation.class);Cost and verification
A change stream holds a server cursor and a client connection. Projection retries and rebuilds consume target-index capacity; retain only the cursor state needed for recovery.
Common Mistakes
- Do not acknowledge progress before the target projection is durable.
- Do not assume a change stream is available on a standalone MongoDB server.
- Do not treat an expired resume token as permission to skip missed data.
Read next
Spring Data MongoDB optimistic locking: save the version you read, Spring outbox retry budget: park a poison event for inspection, Spring WebSocket reconnect: recover state after an unobserved gap, Spring Data Elasticsearch mapping rollout: build a new index, then move the read alias.
Related boundary
Spring Data Elasticsearch write versus search: refresh is the visibility boundary
Related boundary
Spring Data Cassandra paging state: continue the same bounded query
