deliveries and history.
What changes in MongoDB
Version 1 keeps attempts inorionjs.pulse.history and the logical outcome in
orionjs.pulse.deliveries. That model remains available for ordered consumers and for compatibility.
Version 2 keeps the attempt state on the delivery:
v2-pendingis ready now or waiting fornextAttemptAt.v2-processingowns a renewable lease and fencing token.v2-successandv2-errorare terminal.- The most recent 10 completed outcomes are kept in
delivery.attempts;delivery.attemptremains the exact total attempt number. Errors are size-bounded so the document cannot grow with an unbounded retry configuration. - The outcome is appended in the same atomic write that schedules a retry or makes the delivery terminal.
v2-* states are part of the rolling-deploy protocol. Older Pulse binaries only query
the original pending, success, and error states, so they cannot claim, reconcile, or delete a
version 2 delivery.
The unique {consumerGroup, eventId} index still creates exactly one logical delivery. If old and
new discovery leaders see the same event during a rollout, whichever upsert wins chooses that
event’s format. Bridge-capable workers drain both formats; an in-flight delivery is never converted.
pulse.history.find() merges original history documents with attempts projected from version 2
deliveries, so application code keeps the same public history API. For version 2 it exposes the
bounded recent-attempt window rather than an unlimited retry history. Version 2 does not add
documents to the physical history collection.
Safe production rollout
Use two deployments. Do not enable version 2 in the first one.- Upgrade every consumer replica to the bridge-capable Pulse package. Leave
executionVersionomitted, which continues to mean version 1. - After the bridge is everywhere, set
executionVersion: 2on selected unordered listeners and increase theirconfigVersion.
@orion-js/pulse-bridge-v2. Where the production database role permits currentOp, use that
metadata together with deployment telemetry to confirm the first phase; do not infer completion
from the subscription document alone.
The second deployment may be gradual. Replicas with the lower configuration adopt the higher
persisted configVersion; bridge workers continue to execute the remaining version 1 backlog while
newly materialized events converge on version 2.
If a later configuration also changes ordering, deliveries already born as version 2 retain their
unordered semantics while the bridge drains them. Ordering changes apply to newly materialized
version 1 deliveries; Pulse never rewrites an in-flight delivery’s execution format.
Activate a few consumer groups first and compare handler throughput, MongoDB writes, query latency,
and lock recovery before expanding the change. The two new partial indexes keep only the active
version 2 queue states:
v2-* delivery queries for rollout monitoring; application code using
pulse.history.find() does see the recent version 2 attempts.
Rollback
Rollback the configuration before rolling back the bridge package:- Set
executionVersion: 1with a new, higherconfigVersion. - Keep the bridge fleet running until the affected consumer groups have no
v2-pendingorv2-processingdeliveries. - Only then deploy a package version that predates the bridge, if that is still necessary.
Retention and recovery
The active lease is renewed on the delivery and every acknowledgement is fenced by itslockToken.
If a worker disappears, a compare-and-set update appends a worker_lost attempt and either schedules
the next retry or makes the delivery terminal. A stale worker cannot acknowledge after recovery has
changed the state or token.
Terminal version 2 deliveries receive expiresAt in the same write as their final attempt. The
existing TTL index removes the whole execution record after historyRetentionMs. With
historyRetentionMs: null, Pulse omits expiresAt and retains it indefinitely.
See Consuming events for subscription configuration and
Reliability and recovery for the complete execution
model.