Event-driven architecture inverts the typical request-response flow — instead of Service A directly calling Service B, Service A publishes an event, and anything interested reacts to it, without A ever knowing who’s listening.
# Traditional: OrderService directly calls each dependent service
class OrderService:
def place_order(self, order):
self.save(order)
self.email_service.send_confirmation(order) # tightly coupled
self.inventory_service.reduce_stock(order) # tightly coupled
self.analytics_service.track(order) # tightly coupled
# Event-driven: OrderService just announces what happened
class OrderService:
def place_order(self, order):
self.save(order)
event_bus.publish("order.placed", order) # doesn't know or care who's listening
# Elsewhere, entirely decoupled - can be added/removed independently
event_bus.subscribe("order.placed", email_service.send_confirmation)
event_bus.subscribe("order.placed", inventory_service.reduce_stock)
event_bus.subscribe("order.placed", analytics_service.track)
The Real Trade-off
Event-driven systems decouple services well and scale independently, but debugging becomes genuinely harder — tracing “what happened when this order was placed” now means following events across multiple independent consumers rather than reading one linear call stack. Distributed tracing tools become close to mandatory once a system grows past a handful of event consumers.