Bird
Raised Fist0
Microservicessystem_design~7 mins

Event-driven vs request-driven in Microservices - Architecture Trade-offs

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Problem Statement
When services communicate only by direct requests, a slow or failing service can block the entire flow, causing delays and failures. This tight coupling makes the system fragile and hard to scale under varying loads.
Solution
Event-driven architecture decouples services by using events to signal changes or actions asynchronously. Instead of waiting for a response, services emit events that others listen to and react upon, allowing independent scaling and failure isolation.
Architecture
Service A
Event Broker
Service B
Service B
Client
Service A

The diagram shows two communication styles: event-driven where Service A emits events to an event broker that Service B consumes asynchronously, and request-driven where a client sends a request to Service A and waits synchronously for a response.

Trade-offs
✓ Pros
Event-driven allows services to operate independently, improving fault tolerance.
It supports asynchronous processing, which can improve system throughput and responsiveness.
Request-driven is simpler to implement and easier to reason about for synchronous workflows.
Request-driven provides immediate feedback to clients, useful for real-time interactions.
✗ Cons
Event-driven systems can be harder to debug due to asynchronous flows and eventual consistency.
They require infrastructure like message brokers and careful event schema management.
Request-driven systems can become bottlenecks if services are slow or fail, impacting user experience.
Tight coupling in request-driven can reduce system resilience and scalability.
Use event-driven when services need loose coupling, asynchronous processing, or must handle high throughput and variable loads. Use request-driven for simple, synchronous interactions requiring immediate responses, especially under low to moderate load.
Avoid event-driven if your system requires strict immediate consistency or if debugging complexity is unacceptable. Avoid request-driven when services are highly interdependent or when scaling to high concurrency and fault tolerance is critical.
Real World Examples
Netflix
Uses event-driven architecture to decouple microservices for streaming and recommendations, allowing independent scaling and resilience.
Uber
Employs request-driven APIs for synchronous ride requests but uses event-driven patterns for asynchronous updates like trip status and notifications.
Amazon
Combines request-driven APIs for order placement with event-driven workflows for inventory updates and shipment processing.
Code Example
The before code shows a synchronous request where ServiceA calls ServiceB and waits for the result. The after code uses an event broker where ServiceA publishes an event and ServiceB subscribes to handle it asynchronously, decoupling the services.
Microservices
### Before: Request-driven (synchronous call)
class ServiceA:
    def process(self, data):
        result = ServiceB().handle(data)
        return result

class ServiceB:
    def handle(self, data):
        return f"Processed {data}"

# Usage
service_a = ServiceA()
response = service_a.process('input')
print(response)


### After: Event-driven (asynchronous event emission)
import queue

class EventBroker:
    def __init__(self):
        self.subscribers = []
        self.events = queue.Queue()

    def subscribe(self, handler):
        self.subscribers.append(handler)

    def publish(self, event):
        self.events.put(event)

    def dispatch(self):
        while not self.events.empty():
            event = self.events.get()
            for subscriber in self.subscribers:
                subscriber(event)

class ServiceA:
    def __init__(self, broker):
        self.broker = broker

    def process(self, data):
        self.broker.publish({'type': 'process', 'data': data})

class ServiceB:
    def __call__(self, event):
        if event['type'] == 'process':
            print(f"Processed {event['data']}")

# Setup
broker = EventBroker()
service_b = ServiceB()
broker.subscribe(service_b)
service_a = ServiceA(broker)

# Usage
service_a.process('input')
broker.dispatch()
OutputSuccess
Alternatives
Synchronous request-response
Direct calls with immediate responses, tightly coupling services.
Use when: When operations require immediate results and system scale is manageable.
Batch processing
Processes data in large groups at scheduled times instead of real-time events.
Use when: When real-time processing is not required and throughput optimization is prioritized.
Summary
Request-driven architecture uses direct synchronous calls, suitable for immediate responses but can cause tight coupling and bottlenecks.
Event-driven architecture decouples services with asynchronous events, improving scalability and fault tolerance but increasing complexity.
Choosing between them depends on system requirements for consistency, latency, scalability, and complexity.

Practice

(1/5)
1. Which statement best describes an event-driven microservice architecture?
easy
A. Services communicate by sending messages without waiting for immediate responses.
B. Services make direct calls and wait for responses before continuing.
C. Services share a common database to exchange data synchronously.
D. Services use batch processing to handle requests at fixed intervals.

Solution

  1. Step 1: Understand event-driven communication

    Event-driven systems use messages or events to notify other services asynchronously, without waiting for a reply.
  2. Step 2: Compare with request-driven communication

    Request-driven systems make direct calls and wait for responses, which is synchronous communication.
  3. Final Answer:

    Services communicate by sending messages without waiting for immediate responses. -> Option A
  4. Quick Check:

    Event-driven = asynchronous messaging [OK]
Hint: Event-driven means no waiting for replies, just messages [OK]
Common Mistakes:
  • Confusing event-driven with synchronous calls
  • Thinking event-driven requires shared databases
  • Assuming event-driven always uses batch processing
2. Which of the following is the correct way to describe a request-driven call in microservices?
easy
A. Service A sends an event and continues without waiting.
B. Service A writes data to a shared database for Service B to read later.
C. Service A processes requests in batches asynchronously.
D. Service A calls Service B and waits for a response before proceeding.

Solution

  1. Step 1: Identify request-driven behavior

    Request-driven means a service calls another and waits for the response before moving on.
  2. Step 2: Eliminate other options

    Options A and D describe asynchronous or event-driven behavior; Service A writes data to a shared database for Service B to read later. describes shared database, not direct calls.
  3. Final Answer:

    Service A calls Service B and waits for a response before proceeding. -> Option D
  4. Quick Check:

    Request-driven = synchronous call and wait [OK]
Hint: Request-driven means wait for reply before continuing [OK]
Common Mistakes:
  • Mixing event-driven with request-driven
  • Thinking shared database equals request-driven
  • Confusing batch processing with request-driven calls
3. Consider this scenario: Service A sends an event to a message broker, and Service B listens and processes it asynchronously. What is the main advantage of this design?
medium
A. Service B can process events at its own pace without blocking Service A.
B. Service B must respond immediately to Service A's request.
C. Service A and B share the same database for faster communication.
D. Service A waits for Service B to finish processing before continuing.

Solution

  1. Step 1: Analyze asynchronous event processing

    Service A sends an event and does not wait; Service B processes independently.
  2. Step 2: Identify the advantage

    This allows Service B to handle events at its own speed without blocking Service A, improving scalability and decoupling.
  3. Final Answer:

    Service B can process events at its own pace without blocking Service A. -> Option A
  4. Quick Check:

    Asynchronous event-driven = decoupled processing [OK]
Hint: Async events let receivers work independently [OK]
Common Mistakes:
  • Assuming sender waits for receiver
  • Confusing shared database with event broker
  • Expecting immediate response in event-driven
4. You have a microservice that calls another service synchronously but experiences high latency and failures. Which change can improve reliability using event-driven design?
medium
A. Increase the timeout for synchronous calls to wait longer.
B. Replace synchronous calls with asynchronous events and retries.
C. Use a shared database for both services to read and write data.
D. Batch multiple synchronous calls into one to reduce overhead.

Solution

  1. Step 1: Identify problem with synchronous calls

    High latency and failures occur because the caller waits and depends on the callee's immediate response.
  2. Step 2: Apply event-driven solution

    Switching to asynchronous events decouples services, allowing retries and better fault tolerance without blocking.
  3. Final Answer:

    Replace synchronous calls with asynchronous events and retries. -> Option B
  4. Quick Check:

    Event-driven improves reliability by decoupling [OK]
Hint: Async events with retries reduce blocking and failures [OK]
Common Mistakes:
  • Just increasing timeout doesn't fix failures
  • Shared database doesn't solve latency issues
  • Batching synchronous calls still blocks
5. A company wants to design a microservices system for online orders. They need fast user feedback and flexible processing of orders. Which architecture best fits their needs?
hard
A. Use only request-driven calls for all services to ensure immediate responses.
B. Use only event-driven design for all services to maximize decoupling.
C. Use request-driven calls for order validation and event-driven for inventory updates.
D. Use batch processing to handle orders every hour for efficiency.

Solution

  1. Step 1: Analyze requirements for fast feedback and flexibility

    Fast user feedback needs synchronous validation; flexible processing benefits from asynchronous events.
  2. Step 2: Combine architectures appropriately

    Request-driven calls provide immediate validation; event-driven updates allow inventory to process independently and scale.
  3. Final Answer:

    Use request-driven calls for order validation and event-driven for inventory updates. -> Option C
  4. Quick Check:

    Mix sync for speed + async for flexibility [OK]
Hint: Mix sync for fast feedback, async for flexible tasks [OK]
Common Mistakes:
  • Using only event-driven delays user feedback
  • Using only request-driven limits scalability
  • Batch processing is too slow for online orders