Messaging & Stream Processing
Event-Driven Architecture
Services communicate by publishing facts about what happened ("OrderPlaced") instead of calling each other directly — trading immediate consistency and simple call chains for loose coupling and independent scaling of producers and consumers.
- Inversion of control: a service announces what happened and does not know (or care) who reacts to it, versus RPC where the caller explicitly invokes and waits on each dependency
- Buys temporal decoupling (consumers can be down and catch up later) and deployment decoupling (new consumers can be added without touching the producer)
- Costs eventual consistency everywhere — there is no moment where "everything downstream has processed this event" is true by construction
- Event schemas are now a public contract between services that evolve independently — the same versioning discipline as any external API
- The "distributed monolith" anti-pattern: services technically decoupled via events but still implicitly coupled through shared assumptions about event ordering, timing, or payload shape
The tradeoff is visible the moment something goes wrong: in a direct RPC chain, a failure in the shipping call is immediately visible to the order service, which can retry or roll back synchronously. In an event-driven chain, OrderPlaced is published successfully, and the shipping service failing to process it later is invisible to the order service entirely — there is no caller waiting on a response to fail. Detecting and recovering from that failure needs its own explicit machinery: dead-letter queues, monitoring on consumer lag, and often a saga or compensating-action pattern instead of a rollback.