Event-Carried State Transfer
The event carries a snapshot of the business state, not just its identifier — downstream no longer needs to call back upstream synchronously.
Problem
In a naive event-driven architecture, the emitter publishes a notification event ("OrderConfirmed#42"). Each consumer must then call the producer's API to fetch the full order state. The system regains a strong synchronous coupling: if the producer is down, consumers are blocked; if 50 consumers react, load is amplified by 50.
Forces
- Synchronous consumer ↔ producer coupling reintroduces the cascading failures event-driven design aimed to avoid.
- Embedding all data in the event grows message size and pressure on the broker.
- An event with snapshot is self-contained: an offline replay rebuilds historical state.
- Snapshot freshness is frozen at emission — consumers must handle invalidation when a newer event exists.
- Schemas evolve: an old consumer must ignore new fields without crashing.
Solution
Include in the event a payload that fully describes the modified aggregate at time T. Consumers maintain their local copy (cache, materialized view) by reacting to successive events. Golden rule: an event must be sufficient to reconstruct downstream-needed state — no need to call the producer back. To manage size, combine with Claim Check when the snapshot exceeds a few KB.
Structure
Producer (Order Service)
│ COMMIT (DB + event in same TX, see Outbox)
▼
┌─────────────────────────────────────────────────┐
│ Event: OrderUpdated │
│ id: order-42, version: 7, timestamp: ... │
│ state: { customer, items[], totals, status } │ ← full snapshot
└───────────┬──────────────────────┬──────────────┘
▼ ▼
Consumer A (Billing) Consumer B (Logistics)
updates local cache updates local view
no call to Producer no call to Producer EDI implementation
In an EDI hub, ECST is useful to replicate partner state (PartnerProfileUpdated with the full profile: AS2 URL, certificate, OFTP2 SSID, EAS code), or to push transactions to an analytics lake without coupling the lake to the OLTP layer. An InvoiceIssued event embedding the complete UBL lets a fiscal connector (PEPPOL CTC) consume without calling the ERP. Conversely, for high-volume flows where only the identifier matters (DispatchedRow), stay with Event Notification.
Anti-patterns
- Anemic snapshot — downstream must call upstream for details; no gain.
- Obese snapshot — every event embeds full history, broker saturates.
- No version number — consumer cannot detect that a newer event already updated state (out-of-order delivery).
- No schema evolution strategy — a new field breaks an old consumer.
- Snapshot with unfiltered PII — analytics lake receives data it should not see (GDPR).
Related patterns
- Event Notification — minimal alternative without payload.
- Event Sourcing — reuses the same event log but with definitive persistence.
- Claim Check — externalises the snapshot when it grows too big.
- Outbox — guarantees atomic DB + event write.
Sources
- Fowler M. — What do you mean by "Event-Driven"?, 2017. martinfowler.com/articles/201701-event-driven.html
- Newman S. — Building Microservices, 2nd ed., O'Reilly 2021, ch. 4 "Microservice Communication Styles".
- Kleppmann M. — Designing Data-Intensive Applications, O'Reilly 2017, ch. 11 "Stream Processing".