Microservices Communication Patterns
Synchronous vs Asynchronous
Synchronous (REST/gRPC):
+ Simple request/response
+ Immediate feedback
- Tight coupling (caller waits)
Use for: User-facing queries, real-time data needs
Asynchronous (Message Queue):
+ Loose coupling
+ Better fault isolation
- Eventual consistency
Use for: Commands, notifications, data sync
gRPC Schema
syntax = "proto3";
service UserService {
rpc GetUser(GetUserRequest) returns (UserResponse);
rpc ListUsers(ListUsersRequest) returns (stream UserResponse);
}
message GetUserRequest { string id = 1; }
message UserResponse {
string id = 1;
string email = 2;
string name = 3;
}
Message Queue Patterns
Command Pattern (one-to-one)
// Order service sends command to inventory
await messageQueue.send('inventory.reserve', {
orderId: order.id,
items: order.items,
}, { messageId: generateId() }); // idempotency key
// Inventory service processes command
consumer.subscribe('inventory.reserve', async (msg) => {
if (await processedMessages.has(msg.messageId)) return; // Already handled
await inventoryService.reserve(msg.payload.items);
await processedMessages.add(msg.messageId);
await messageQueue.send('inventory.reserved', { orderId: msg.payload.orderId });
});
Event Pattern (one-to-many)
// User service publishes event
await eventBus.publish('user.registered', { userId: user.id, email: user.email });
// Multiple services subscribe independently
eventBus.subscribe('user.registered', async (e) => emailService.sendWelcome(e.email));
eventBus.subscribe('user.registered', async (e) => analytics.track('signup', e));
Circuit Breaker
class CircuitBreaker {
private failures = 0;
private state: 'closed' | 'open' | 'half-open' = 'closed';
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === 'open') throw new Error('Circuit breaker is open');
try {
const result = await fn();
if (this.state === 'half-open') this.reset();
return result;
} catch (err) {
this.failures++;
if (this.failures >= 5) this.state = 'open';
throw err;
}
}
private reset() { this.failures = 0; this.state = 'closed'; }
}
Saga Pattern (Distributed Transactions)
Order Placed
-> Payment Charged
-> Inventory Reserved
-> Shipping Scheduled
-> Order Confirmed
If Shipping Fails:
-> Inventory Released (compensating transaction)
-> Payment Refunded (compensating transaction)
-> Order Failed
Start with a monolith, extract services when you have clear domain boundaries.