Event-Carried State Transfer

An event-driven pattern where events carry the complete relevant state in their payload, enabling consumers to process events without making follow-up calls to the publisher — achieving full temporal decoupling.

Problem

Event Notification (thin events) requires consumers to call back to get state, creating latency and availability coupling: if the publisher is down when the consumer processes the event, the consumer cannot proceed. How do you decouple consumers from needing the publisher to be available at processing time?

Solution / Explanation

The publishing service includes all state the consumer needs in the event payload itself:

Typical ECST payload:

{
  "type": "OrderPlaced",
  "orderId": "ord-12345",
  "timestamp": "2026-05-06T10:00:00Z",
  "customerId": "cust-789",
  "items": [
    {"productId": "prod-101", "quantity": 2, "price": 29.99},
    {"productId": "prod-202", "quantity": 1, "price": 49.99}
  ],
  "shippingAddress": { "street": "...", "city": "..." },
  "totalAmount": 109.97
}

The consumer has everything it needs to:

  • Update its local read model / cache
  • Trigger downstream business logic
  • Respond to the customer

No follow-up call needed.

Characteristics

AspectValue
Payload sizeFull state — potentially large
Consumer autonomyComplete — no dependency on publisher at processing time
Temporal decouplingFull — consumer processes events from queue asynchronously
Data freshnessState in event is current at time of publication; may be stale by processing time
Local cachingConsumers maintain local copies of foreign-domain state

Local Cache Pattern

Consumers often maintain a local projection of relevant data from the publishing domain. This eliminates synchronous cross-service queries entirely:

Order Service publishes OrderPlaced (with full product + customer state)
     ↓
Warehouse Service maintains local product catalog cache (updated via events)
Warehouse never calls Product Service synchronously

This is a key pattern in CQRS read models — projections built from event streams.

When to Use

  • Consumers are downstream services that cache foreign-domain state (e.g., a shipping service caching customer addresses)
  • High event throughput — eliminating follow-up calls is critical for performance
  • Circuit breaker isolation — consumers must work even when publishers are down
  • Events are published to a durable event stream (Kafka) where reprocessing is possible

Risks

State drift: If a consumer misses an event or processes them out of order, its local cache becomes inconsistent. Mitigation: use event sequence numbers; design for idempotency.

Large payload size: For events with extensive state, payload size can be a concern. Use schema registries for efficient serialization (Avro, Protobuf).

Schema evolution: When the publisher changes its event schema, all consumers must update. Use Event Upcasting to handle schema migration.

Trade-offs

BenefitCost
Full temporal decouplingLarge event payloads
No follow-up calls (low latency)State may be stale by processing time
Consumers work even when publisher is downSchema evolution affects all consumers
Natural CQRS read model buildingLocal caches can diverge from source of truth