ordered: true, and Echoes can choose that behavior independently for
each event listener.
orderCreated is serialized across every replica in its consumer group. analyticsRecorded
inherits Pulse’s unordered default and can use the available worker concurrency.
Why subscription configuration is persisted
Pulse stores one subscription document for eachconsumerGroup + topic. That document contains
the durable cursor as well as ordering, delivery, and retry settings. Persisting the settings keeps
replicas consistent, but previously made intentional changes awkward: a new deployment with a
different value failed because it did not match MongoDB.
configVersion makes the desired change explicit. It is a non-negative integer, and the highest
version wins:
Existing subscriptions
Legacy subscription documents have no version and are treated as version zero. If code omitsordered for an existing topic, Pulse keeps the persisted value. This means upgrading does not
silently turn an existing ordered topic into an unordered one.
For a brand-new topic, omitting both fields creates an unordered version-zero subscription:
What happens during deployment
The change is deliberately lightweight: Pulse does not pause the topic or run a separate migration job. Callbacks that were already claimed finish with the previous behavior. New work converges on the highest persisted version as replicas refresh their subscription documents. That short transition is appropriate when intentionally switching between ordered and concurrent processing. If an application requires a hard boundary with no overlap at all, drain or stop its consumer replicas before deploying the higher version.Recovery no longer runs in the backlog hot loop
Pulse now schedules runtime maintenance independently from event discovery and execution:- Reconciliation normally runs every 30 seconds and reads only documents marked with
needsReconciliationthrough small partial indexes. - Expired attempts are checked near the next known lock deadline instead of on every coordinator iteration.
- Recovery fetches related deliveries and histories in bounded batches instead of issuing one lookup for every delivery.
pending, success, and error deliveries while a backlog is draining.
Completed delivery cleanup
The discovery leader periodically removes up to 1,000 successful deliveries from a rotating set of topics. A delivery is eligible only when its persisted subscription cursor has reached that event. Pulse handles the MongoDB sequence cursor and the legacycreatedAt + eventId cursor
independently.
When historyRetentionMs is enabled, cleanup also requires delivery.expiresAt. This field proves
that retention was already applied to the delivery and its completed history before the delivery
is removed. With historyRetentionMs: null, no expiresAt marker is required. Cleanup never reads
the history collection and runs on its own 60-second cadence, outside the coordinator hot loop.
Production upgrade
Upgrade services in two phases when changing an existing topic’s ordering:- Upgrade every replica to
@orion-js/pulse@4.5.9and@orion-js/echoes@4.5.4without changing the topic configuration. Existing subscriptions keep their persisted ordering. - After all replicas run the new packages, deploy the intended
orderedvalue with a higherconfigVersion.
configVersion out of the configuration transition.
Pulse creates and validates the new partial reconciliation indexes during startup. On a large
MongoDB deployment, start with one canary replica, wait for awaitConnection() to complete, and
check database CPU, disk queue, and index-build progress before rolling the remaining replicas.
After rollout, the old repeated delivery-reconciliation aggregate shapes should disappear from
Query Insights; marker lookups should examine only a small number of documents.
Versioning rules
- Use non-negative integers and increase the number only when durable subscription settings change.
- A higher version replaces a lower version atomically.
- A lower version adopts the persisted winner and never downgrades it.
- Different settings at the same version throw
PulseConfigurationError. - Omitting the version means version zero.
maxConcurrencyremains local to each process and is not part of the persisted configuration.