Course contentsShow
← Node.js
Lesson 1242 of 1,98011. Task Queues and Background ProcessingFree lesson

Designing Eventual Consistency Models

Reconcile state asynchronously between distributed services using event sourcing.

In this lesson, you will learn how to leverage event sourcing to reconcile state asynchronously across distributed Node.js services.

The Problem: Distributed Drift

In a distributed system, a single user action—like updating a profile—might affect services for Billing, Notifications, and Analytics. If you try to update these synchronously, a network hiccup or a slow database in one service can lead to inconsistent state. "Eventual consistency" acknowledges that these services may be temporarily out of sync, provided they all arrive at the same final state eventually.

Reconciliation via Event Sourcing

Instead of pushing "current state" (e.g., user.status = 'active'), we communicate through an immutable log of events: { event: 'UserActivated', userId: '123', timestamp: '...' }.

In this model, your services act as event processors. Each service maintains its own local projection (a database view) derived from the stream of events. If a service goes offline, it simply "replays" the events it missed once it reconnects.

Example: Syncing a Read Model

Imagine an Order service emitting an event, and a Shipping service consuming it to update its local state.

// Order Service: Emitting the truth
const event = { type: 'ORDER_PLACED', id: 'abc', items: ['book'] };
await messageBroker.publish('orders', event);

// Shipping Service: Reconciling its state
messageBroker.subscribe('orders', (event) => {
  if (event.type === 'ORDER_PLACED') {
    // We reconcile asynchronously. Even if this db write is delayed,
    // the system remains consistent over time.
    db.shipping_logs.insert({ orderId: event.id, status: 'pending' });
  }
});

Why it Works

By treating the event stream as the "single source of truth," you decouple services. If the Shipping service fails, it doesn't block the Order service. Once back online, the Shipping service consumes the pending events in the log to catch up, effectively reconciling its local state with the global event history. This avoids distributed transactions, which are notoriously difficult to scale in Node.js architectures.

Key Takeaway: Rather than forcing immediate consistency across services, use an immutable event log as the source of truth, allowing each service to asynchronously reconcile its own state by replaying and processing events.