Choose the right communication pattern between microservices for each use case. Covers synchronous REST/gRPC, asynchronous messaging, event-driven architecture, saga patterns, the tradeoffs between consistency and availability, and the decision framework that prevents you from over-engineering simple integrations.
This reference explains how microservices communicate using synchronous, asynchronous, and event-driven approaches. These patterns determine how services interact, what happens when communication fails, and how systems scale under load. Understanding these patterns is critical when designing service boundaries, handling failures, and implementing reliable distributed systems.
Synchronous communication occurs when a service makes a request and waits for a response before continuing. This pattern is most common with HTTP APIs.
A client service sends an HTTP request to another service:
curl -X POST \
http://user-service:8080/users \
-H 'Content-Type: application/json' \
-d '{"name": "Alice", "email": "[email protected]"}'
The receiving service must respond with a status code and body before the client proceeds. If the service does not respond within a timeout, the client may time out.
When timeouts occur, services should fail fast rather than wait indefinitely:
curl --max-time 5 \
http://order-service:8080/orders/12345
A timeout response looks like:
curl: (28) Operation timed out after 5001 milliseconds with 0 bytes received
The client must distinguish between a timeout and a service returning an error. A timeout indicates network or resource issues, while a 5xx error from the service means it handled the request but failed.
Services should return appropriate HTTP status codes:
A service returning a 500 error may include JSON in the body:
{
"error": "Database connection failed",
"code": "DB_CONNECTION_ERROR"
}
Synchronous calls can cause deadlocks when services call each other in cycles. If service A calls B, and B calls A, both wait indefinitely.
Asynchronous communication uses message queues to decouple services. The sender places a message and continues without waiting for a response.
Messages are placed in a queue by producers. Consumers process messages from the queue:
# Example of sending a message via a queue client
echo '{"userId": 123, "action": "create_account"}' | \
rabbitmqctl publish -q user_events -e application/json
Consumers pull messages and process them. If processing fails, the message can be retried or moved to a dead-letter queue:
# Example of consuming from a queue
rabbitmqctl get -q user_events -c 10
Messages that fail processing should be retried with exponential backoff. A failed message may be retried after 1 second, then 2 seconds, then 4 seconds, and so on.
Consumers must acknowledge messages when they are successfully processed:
# Manual acknowledgment in a queue consumer
rabbitmqctl get -q user_events --ack
If a message is not acknowledged, it remains in the queue and can be re-delivered.
Messages that repeatedly fail processing are called poison messages. These should be moved to a dead-letter queue rather than being retried infinitely:
# Configuration for dead-letter exchange
rabbitmqctl set_policy --priority 1 \
--pattern "^user_events$" \
--definition '{"dead-letter-exchange":"dlx"}' \
user_events
Event-driven communication uses events to signal state changes. Services react to events rather than calling each other directly.
Services publish events when significant actions occur:
curl -X POST http://event-bus:8080/events \
-H 'Content-Type: application/json' \
-d '{
"type": "user.created",
"data": {
"userId": 123,
"name": "Alice"
},
"timestamp": "2023-05-15T10:00:00Z"
}'
Other services subscribe to specific event types:
# Example of subscribing to events via HTTP webhook
curl -X POST http://event-bus:8080/subscriptions \
-H 'Content-Type: application/json' \
-d '{
"event_type": "user.created",
"url": "http://notification-service:8080/webhook"
}'
Events should be delivered at least once. Duplicate events are acceptable but must not cause data corruption.
Events should include version information to handle schema changes:
{
"type": "user.created.v2",
"data": {
"userId": 123,
"name": "Alice",
"email": "[email protected]"
},
"version": "2.0",
"timestamp": "2023-05-15T10:00:00Z"
}
Timeouts in synchronous calls cause immediate failure. The client must retry or handle the timeout gracefully.
A service that times out on a request should return a 504 Gateway Timeout:
HTTP/1.1 504 Gateway Timeout
Content-Type: application/json
{
"error": "Request timed out",
"service": "user-service"
}
Failed message processing in asynchronous systems may cause:
Consumers should implement circuit breaker patterns to avoid cascading failures.
Events can be lost or duplicated. Services must handle both cases:
Services should configure retry behavior explicitly:
# Example retry configuration for HTTP calls
retry:
max_attempts: 3
backoff_seconds: 1
jitter: true
Queues should implement backpressure mechanisms to prevent memory exhaustion:
# Configure queue size limits
rabbitmqctl set_parameter --vhost / \
queue_max_length 10000
Messages may have time-to-live settings:
# Set message expiration after 30 seconds
rabbitmqctl publish -q user_events \
--expiration 30000 \
'{"userId": 123}'
Real systems often use combinations of patterns. For example, a service might:
Implement circuit breakers to prevent cascading failures:
# Example: Circuit breaker configuration
curl -X POST http://circuit-broker:8080/circuits \
-H 'Content-Type: application/json' \
-d '{
"name": "user-service",
"timeout": 5000,
"failure_threshold": 3,
"reset_timeout": 30000
}'
All communication patterns should include monitoring:
Services must ensure idempotency where possible, especially in asynchronous systems:
# Example of idempotent operation
curl -X POST http://payment-service:8080/payments \
-H 'Content-Type: application/json' \
-H 'X-Request-ID: abc123' \
-d '{"amount": 100, "reference": "order-123"}'
The X-Request-ID header allows services to detect and ignore duplicate requests.
This page was rewritten on 15 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy