Microservices Patterns
Core Patterns
| Pattern | Problem Solved | How It Works |
|---|---|---|
| API Gateway | Client talks to many services | Single entry point; routes, auth, rate-limit, aggregates |
| Circuit Breaker | Cascading failures | Opens after N failures; fast-fails; half-open probe |
| Saga | Distributed transactions | Chain of local transactions + compensating transactions |
| CQRS | Read/write contention | Separate read model from write model |
| Event Sourcing | Audit trail, time travel | Store events, not state; rebuild state from event log |
| Outbox Pattern | Dual write (DB + message) atomicity | Write to DB outbox table; relay publishes to broker |
| Strangler Fig | Migrating monolith incrementally | Route new features to new service; retire old code piece by piece |
| Sidecar | Cross-cutting concerns per pod | Co-deploy proxy (Envoy/Linkerd) for observability, auth |
Circuit Breaker Implementation
// Circuit Breaker states: CLOSED โ OPEN โ HALF-OPEN โ CLOSED
class CircuitBreaker {
constructor(fn, { threshold = 5, timeout = 60000, halfOpenRequests = 1 } = {}) {
this.fn = fn;
this.state = 'CLOSED';
this.failureCount = 0;
this.threshold = threshold;
this.timeout = timeout;
this.nextAttempt = null;
}
async call(...args) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttempt) {
throw new Error('Circuit breaker is OPEN');
}
this.state = 'HALF-OPEN';
}
try {
const result = await this.fn(...args);
this.onSuccess();
return result;
} catch (err) {
this.onFailure();
throw err;
}
}
onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failureCount++;
if (this.failureCount >= this.threshold || this.state === 'HALF-OPEN') {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.timeout;
}
}
}
// Usage with resilience4j (Java / Spring Boot)
@CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback")
public PaymentResult processPayment(Order order) { ... }
public PaymentResult paymentFallback(Order order, Exception e) {
return PaymentResult.queued(order.getId()); // degrade gracefully
}
Saga Pattern: Choreography vs Orchestration
// Choreography Saga โ services react to events
// OrderService emits OrderCreated
// PaymentService listens โ emits PaymentProcessed or PaymentFailed
// InventoryService listens โ emits StockReserved or StockFailed
// Each service handles compensating events
// Example event flow:
OrderCreated โ PaymentProcessed โ StockReserved โ OrderConfirmed
โ PaymentFailed โ OrderCancelled
โ StockFailed โ RefundPayment โ OrderCancelled
// Orchestration Saga โ central orchestrator directs steps
class OrderSagaOrchestrator {
async execute(orderId) {
try {
await paymentService.charge(orderId);
await inventoryService.reserve(orderId);
await shippingService.schedule(orderId);
await orderService.confirm(orderId);
} catch (err) {
// Compensate in reverse order
await shippingService.cancel(orderId);
await inventoryService.release(orderId);
await paymentService.refund(orderId);
await orderService.cancel(orderId);
}
}
}