Beginner System Architecture

Event-Driven Architecture

In an event-driven architecture, parts of the system communicate by emitting and reacting to events instead of calling each other directly. An event is a fact that already happened, like “OrderPlaced” or “PaymentReceived”. This decouples senders from receivers and lets systems work asynchronously.

Producers and consumers

A producer publishes an event without knowing who will handle it. A consumer subscribes and reacts. A broker (a queue or message bus) sits in the middle.

Producer  -->  [ Broker / Queue ]  -->  Consumer A
                                   -->  Consumer B

The producer fires and forgets. Consumers process at their own pace.

Queues vs pub/sub

There are two common patterns.

Queue (work distribution):
  Producer -> [ msg1 msg2 msg3 ] -> one worker takes each message

Pub/Sub (broadcast):
  Producer -> Topic -> Subscriber 1
                    -> Subscriber 2
                    -> Subscriber 3

With a queue, each message is handled once by one worker, good for spreading work. With pub/sub, every subscriber gets a copy, good for notifying many systems.

A concrete flow

User places order
  -> "OrderPlaced" event published
       -> Inventory service reserves stock
       -> Email service sends confirmation
       -> Analytics service records the sale

The order service does not call the other three. It just announces what happened.

Advantages

  • Loose coupling: services evolve independently.
  • Resilience: if a consumer is down, messages wait in the queue.
  • Scalability: add more consumers to handle load.
  • Easy to add new reactions without touching the producer.

Disadvantages

  • Harder to trace a flow across many services.
  • Eventual consistency: things update slightly later, not instantly.
  • You must handle duplicate and out-of-order messages.
  • More moving parts to operate and monitor.

When to use it

Choose event-driven design when actions naturally trigger side effects, when you need to decouple teams, or when spikes in load require buffering. Avoid it for simple request/response flows where a direct call is clearer.