ARC 3Understand Replication and RepairChapters 10โ€“14

Chapter 13 โ€” ChangeStream Backpressure and Overflow

Chapter objective: After this chapter, a developer can choose ChangeStream capacity, origins, and overflow behavior explicitly, and make drops, blocking, and callback timeouts observable.

Learning objectives

  1. Separate collection convergence from ChangeStream delivery.
  2. Explain bounded buffering as a stability boundary.
  3. Compare DROP_OLDEST, DROP_NEWEST, BLOCK, and ERROR.
  4. Select origins and failure behavior for a consumer's purpose.

Prerequisites

Case progress

Metrics Adapter sends route-hints changes to a slowing diagnostics dashboard. The collection continues updating while the consumer falls behind. The team decides whether to drop older or newer observations, block briefly, or report an explicit error.

Choosing behavior when the buffer is full

Bounded ChangeStream buffer and overflow policies

ChangeStreamOptions defaults to local and remote events, capacity 1024, DROP_OLDEST, a one-second block limit, and a five-second subscriber callback limit. The defaults bound resource use; they do not replace a business choice.

Policy Full-buffer behavior Suitable use Main cost
DROP_OLDEST discard oldest, admit newest UI refresh and current-state hints incomplete intermediate changes
DROP_NEWEST keep queued events, reject newest short FIFO work preserving its prefix increasingly stale current view
BLOCK wait for capacity until timeout controlled consumer tolerating short jitter producer waits; timeout can still drop
ERROR raise a structured overflow error validation/control path forbidding silent loss caller handles failure

These policies change the observation stream, not the committed collection value. After a stream drops an event, register.get(key) can still return the latest value. A current-state consumer rereads the collection instead of assuming event completeness.

Origin filtering is part of the contract

Event origin distinguishes a local operation from a remote delta. Local-only observation can confirm actions on one node; local plus remote helps diagnose convergence. Disabling both has no meaning and the constructor rejects it.

For the running case, the diagnostics dashboard labels both origins. A local publishing aid may watch local events only, while remaining separate from the transaction audit source. Repair validation combines events with a final collection read.

A slow callback cannot hold the publisher indefinitely

A push subscriber callback also has a timeout and reports excess duration through onError. A stable design keeps the callback to a fast handoff, places slow IO in a separate bounded executor, and records low-cardinality overflow and callback-timeout metrics.

Counterexample and fault injection

Set capacity to one and publish two changes without consuming. DROP_OLDEST retains the second, DROP_NEWEST retains the first, BLOCK waits and then records overflow on timeout, and ERROR raises a structured error. The consumer's need for current view, ordered prefix, or explicit failure determines the policy.

Experiment

cd submodule/dsm
mvn -q -pl dsm-runtime -am \
  -Dtest=BufferedChangeStreamTest,InMemoryDsmRegisterTest \
  -Dsurefire.failIfNoSpecifiedTests=false test

Complete overflow-cases.json with the retained event, producer outcome, and required metric for all four policies.

Experiment acceptance card

Field Content
Command The focused Maven tests above; node --test tests/chapter-assets.test.mjs
Input or fault capacity one, two events, slow consumer, and timed-out callback
Observable result the four policies retain/reject differently; overflow and callback timeout are visible
Evidence level E2: collection and buffer behavior tests
This experiment does not prove Durable ChangeStream history, cross-process exactly-once, or sufficient production capacity

Review

Next

Chapter 14 combines the failure windows: during a partition both nodes can return local success, and repair cannot revoke business commitments already made.