Available Modes
| Mode | Coordination | Events per Instance | Use Case |
|---|---|---|---|
ALL_INSTANCES | None | All events | Cache invalidation, local state, projections |
SINGLE_LEADER | MongoDB lock | All events (leader only) | Order processing, billing, unique side effects |
ALL_INSTANCES (Default)
Every instance processes every event independently. No coordination between instances.When to use
- Local cache invalidation
- In-memory state refresh
- WebSocket push notifications (each server notifies its own clients)
- Read-model / CQRS projections where each instance maintains its own view
SINGLE_LEADER
Only one instance (the leader) processes events. Other instances are on standby and automatically take over if the leader fails.How it works
Leader election
On startup, each instance attempts to acquire a lock in the
_fw_locks MongoDB collection using an atomic findOneAndUpdate. The first instance to succeed becomes the leader.Failover
If the leader crashes or loses connectivity, it stops renewing the lock. After the TTL expires, a standby instance acquires the lock and starts the stream — resuming from the last checkpoint.
Lock document
FlowWarden stores one document per stream in the_fw_locks collection:
The
_fw_locks collection is created automatically. No migration or manual setup required. For non-MongoDB lock backends — including the Redis-backed implementation from flowwarden-redis — see the LockService SPI reference.Timing parameters
| Parameter | Value | Description |
|---|---|---|
| Lock TTL | 60s | Time before an unrenewed lock expires |
| Heartbeat interval | 15s | How often the leader renews its lock |
| Standby poll interval | 20s | How often standby instances check for an expired lock |
| Max failover time | ~80s | Worst case: lock just renewed (60s TTL) + poll interval (20s) |
When to use
- Order processing, billing, payment webhooks
- Email/SMS notifications that must not be duplicated
- Any handler with non-idempotent side effects
- Event-sourced systems where ordering matters globally
Mixed modes
Different streams in the same application can use different deployment modes:SINGLE_LEADER stream has its own independent lock — different streams can have different leaders across your cluster.
Monitoring
When using FlowWarden Console, the stream detail page shows:- Deployment mode badge (
SINGLE LEADERorALL INSTANCES) - Leader role badge per instance (
LEADER/STANDBY) - Instance status cards with role information
StreamMetricsProvider SPI, so they appear in heartbeat data sent to the Console.
Comparison
| Aspect | ALL_INSTANCES | SINGLE_LEADER |
|---|---|---|
| Duplicates | Yes (all instances) | No (leader only) |
| Global ordering | No | Yes |
| Failover delay | None (all always active) | ~20-80s |
| MongoDB overhead | N change streams | 1 change stream + lock heartbeat |
| Idempotency required | Yes | No |
| Coordination | None | _fw_locks collection |
Horizontal scaling beyond these modes
FlowWarden does not partition the change stream across worker instances. If you need event-level parallelism beyond whatSINGLE_LEADER gives you on a single MongoDB collection, the right tools live outside the lib:
- MongoDB sharding upstream — transparent to FlowWarden; the global change stream still works.
- Multiple
@ChangeStreamclasses on different collections — already supported, each runs independently. - Future sink modules (Kafka, RabbitMQ, …) — emit events to a broker and let the broker handle key-based parallelism via consumer groups.
Checkpoint & Resume
Ensure the new leader resumes from the correct position after failover.
Retry & DLQ
Handle failures gracefully with automatic retries and dead letter queues.