Event-Driven Architecture

An event is a record that something happened: customer 4471 placed order 8812 at 14:02:17, a thermostat read 21.5 degrees, a driver accepted a trip. The record names the thing, when it happened and what changed, and it never changes afterwards, because the past does not change. A system built on events writes each record to a shared log once, and every other system that cares reads the log at its own pace.

Request-driven versus event-driven

In a request-driven design, the checkout service finishes an order by calling the inventory service, then the email service, then the analytics service, and waits for each reply. Adding a fraud check means changing checkout again. When the email service is down, the order either fails or checkout grows a retry branch for that one call. In an event-driven design, checkout writes one order_placed event to the log and returns. Inventory, email, analytics and fraud each subscribe to the log and react when they are ready. Checkout holds no list of who reads its events, so a new consumer costs the producer nothing.

One order_placed event, written once. Three readers consume it independently, and the loader lands it in the warehouse within the hour.
  • Checkout service (source, producer)
  • Order event log (queue, append-only topic)
  • Inventory service (consumer, reserves stock)
  • Email service (consumer, sends receipt)
  • Analytics loader (transform, hourly batch)
  • Warehouse (storage, order_events table)
  • Checkout service -> Order event log
  • Order event log -> Inventory service
  • Order event log -> Email service
  • Order event log -> Analytics loader
  • Analytics loader -> Warehouse
Request-driven
  • Producer calls each consumer and waits for a reply
  • Producer code changes when a consumer is added
  • A down consumer blocks or fails the request
  • History lives in server logs nobody queries
Event-driven
  • Producer writes one event and returns
  • Consumers are added without touching the producer
  • A down consumer catches up from its last offset
  • The log is a queryable record of everything that happened

The log sits between producer and consumers, which is why these systems are called decoupled: the 2 sides share a contract about the event, and nothing else.

The shape of an event

Every event carries an envelope, the fields that are the same for every event type, and a payload, the fields specific to this type. The envelope is what routing, deduplication and loading rely on, so it is strict. The payload is what the business reads, so it changes as the business does, and a schema_version in the envelope records which shape the payload has.

FieldPartExampleWhy it is there
event_idenvelopeevt_01HX4K9Q7MDedupe retries, trace one event end to end
event_typeenvelopeorder_placedRoute to the consumers that care
event_timeenvelope2026-10-20T14:02:17ZWhen it happened, stamped by the producer
entity_idenvelopeorder_8812Group every event about one thing
producerenvelopecheckout-v12Trace a malformed event to its source
schema_versionenvelope3Read old payloads with the right code
payloadpayloaditems, total, currencyThe facts specific to this type
{
  "event_id": "evt_01HX4K9Q7M",
  "event_type": "order_placed",
  "event_time": "2026-10-20T14:02:17Z",
  "entity_id": "order_8812",
  "producer": "checkout-v12",
  "schema_version": 3,
  "payload": {
    "customer_id": "cust_4471",
    "items": [
      {"sku": "SKU-220", "qty": 2, "unit_price": 19.99}
    ],
    "total": 39.98,
    "currency": "EUR"
  }
}

Querying an event table

Once the loader lands events in the warehouse, the table has one row per event, and most questions become a count grouped by type and time. This query shows what happened in each hour of one day.

SELECT
  date_trunc('hour', event_time) AS event_hour,
  event_type,
  count(*) AS events
FROM order_events
WHERE event_time >= TIMESTAMP '2026-10-20 00:00:00'
  AND event_time < TIMESTAMP '2026-10-21 00:00:00'
GROUP BY
  date_trunc('hour', event_time),
  event_type
ORDER BY
  event_hour,
  event_type

A payment service must tell inventory, email, fraud and analytics that a refund went through. Which record belongs in the shared log?

About this lesson

This section is part of the Event Streams lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.