Skip to main content

🔔 Event-Driven

React when something happens

The Newspaper Analogy

Two communication styles:

Direct call (phone):

  • You call each person individually
  • They often need to be available right now
  • 10 people = 10 calls

Newspaper (events):

  • Publish your news once
  • Anyone interested subscribes
  • They read when convenient
  • 10 or 10,000 readers - same effort!

Event-driven architecture is publishing, not calling.


What Is Event-Driven Architecture?

Components communicate by producing and consuming events.

Traditional (request-response):
  Service A calls Service B directly.
  A waits for B's response.
  Tightly coupled.

Event-driven:
  Service A publishes "OrderPlaced" event.
  Services B, C, D consume it (if interested).
  A doesn't wait. A doesn't know who listens.
  Loosely coupled!

Core Concepts

Event

A record of something that happened.

{
  "type": "OrderPlaced",
  "timestamp": "<timestamp>",
  "data": {
    "orderId": "123",
    "userId": "456",
    "total": <total>
  }
}

Past tense! "OrderPlaced" not "PlaceOrder"
Immutable fact.

Producer

Service that publishes events.

Order Service → publishes "OrderPlaced"

Doesn't know or care who consumes.

Consumer

Service that subscribes to events.

Inventory Service ← consumes "OrderPlaced"
Email Service ← consumes "OrderPlaced"
Analytics Service ← consumes "OrderPlaced"

Each handles the event independently.

Message Broker

Middleware that routes events.

Producers → Broker → Consumers

Examples: Kafka, RabbitMQ, AWS SNS/SQS

How It Works

Order placed:

┌────────────┐
│   Order    │ ──→ "OrderPlaced" ──→ ┌───────────┐
│  Service   │                        │  Message  │
└────────────┘                        │  Broker   │
                                      └─────┬─────┘
                         ┌─────────────────┼─────────────────┐
                         │                 │                 │
                         ▼                 ▼                 ▼
                   ┌──────────┐     ┌──────────┐     ┌──────────┐
                   │Inventory │     │  Email   │     │Analytics │
                   │ Service  │     │ Service  │     │ Service  │
                   └──────────┘     └──────────┘     └──────────┘

Each service reacts independently.

Patterns

Publish-Subscribe (Pub/Sub)

One event → Multiple subscribers

OrderPlaced event:
  - Inventory: Reduce stock
  - Email: Send confirmation
  - Analytics: Record sale
  - Shipping: Create label

Add new subscriber without changing producer.

Event Streaming

Continuous stream of events.
Consumers process in real-time.

Example: User activity stream
  Click → Scroll → Click → Purchase → ...

Kafka excels here.

Event Sourcing

Store events as source of truth.
Derive current state from event history.

(See Event Sourcing topic for details)

Benefits

1. Loose Coupling

Producer doesn't know consumers.
Add/remove consumers freely.
Services can be developed independently.

2. Scalability

Consumers can process events at their own pace.
High volume? Add more consumer instances.
Broker buffers when consumers are slow.

3. Resilience

Service down? Events wait in broker.
Service recovers? Processes backlog.
Less chance of data loss (when the broker is configured for durability).

4. Real-Time Reactions

Events propagate immediately.
Systems react in real-time.
Analytics, notifications, automation.

Challenges

1. Eventual Consistency

Events take time to propagate.
Consumer may be slightly behind producer.

Not a problem for most cases.
Challenge for strict consistency needs.

2. Debugging Complexity

Request-response: Clear call chain.
Event-driven: Events scatter across services.

Need distributed tracing.
Need event correlation IDs.

3. Ordering

Events may arrive out of order.
Consumer should handle, or the broker should provide ordering guarantees.

Partitioning can help (Kafka).

4. Event Schema Evolution

Events change over time.
Old consumers, new events. New consumers, old events.

Need versioning strategy.

When to Use

Good Fit

✓ Microservices needing to communicate
✓ Real-time data processing
✓ Async operations (email, notifications)
✓ Multiple services react to same event
✓ Scaling read/write independently

Might Be Overkill

✗ Simple CRUD applications
✗ Strong consistency requirements
✗ Single service applications
✗ Tight request-response needs

ToolTypeOften Used For
Apache KafkaStreaming platformHigh volume, durability
RabbitMQMessage brokerTraditional messaging
AWS SNS/SQSCloud messagingAWS ecosystem
Redis Pub/SubIn-memorySimple, fast
NATSLightweightCloud native

Common Mistakes

1. Fat Events

Event with entire object:
  { "order": { ...full order object... } }

Better: Include IDs, consumer fetches if needed.
Or: Just enough data for consumer's needs.

2. No Event Contracts

Producer changes event format.
Consumer breaks.

Define schemas (Avro, Protobuf, JSON Schema).
Version events.

3. Ignoring Failed Events

Event processing fails.
Event discarded.
Data lost!

Use dead letter queues.
Retry with backoff.
Alert on failures.

FAQ

Q: Event-driven vs message-driven?

Very similar! Message-driven focuses on the message exchange mechanism. Event-driven emphasizes domain events as the paradigm.

Q: How do I ensure events are processed once?

Idempotency! Design consumers to handle duplicate events safely.

Q: What about transactions across services?

Use Saga pattern for distributed transactions.

Q: Is Kafka the answer?

It depends. RabbitMQ is great for traditional messaging. Choose based on your needs.


Summary

Event-driven architecture enables loose coupling through asynchronous event communication.

Key Takeaways:

  • Publish events, don't call directly
  • Producers and consumers are decoupled
  • Events stored/routed by message broker
  • Enables scalability and resilience
  • Eventually consistent (trade-off)
  • Tools: Kafka, RabbitMQ, AWS SNS/SQS

Events are the glue that hold modern distributed systems together!

Leave a Comment

Comments (0)

Be the first to comment on this concept.

Comments are approved automatically.