Introduction
When one microservice goes down and others keep calling it, the failure cascades to bring down the entire system. Localize failures with Circuit Breaker and Retry. Generate designs with Claude Code.
CLAUDE.md Microservice Communication Rules
## Microservice Communication Rules
### Required Patterns
- Circuit Breaker: temporarily block calls after consecutive failures (prevent Cascade Failure)
- Retry with Exponential Backoff: only retry transient failures
- Timeout: 3-second timeout on all service calls
- Bulkhead: isolate connection pools per service
### Error Classification
- 4xx (client errors): don't retry (client-side problem)
- 5xx (server errors): retry with exponential backoff
- Timeout/connection errors: retry (via Circuit Breaker)
Generated Circuit Breaker Implementation
// src/clients/circuitBreaker.ts
type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
class CircuitBreaker {
private state: CircuitState = 'CLOSED';
private failureCount = 0;
private lastFailureTime = 0;
private halfOpenSuccessCount = 0;
constructor(
private readonly name: string,
private readonly options = { failureThreshold: 5, recoveryTimeout: 30_000, halfOpenSuccessThreshold: 3 }
) {}
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailureTime > this.options.recoveryTimeout) {
this.state = 'HALF_OPEN';
logger.info({ service: this.name }, 'Circuit breaker: OPEN → HALF_OPEN');
} else {
throw new ServiceUnavailableError(`Circuit breaker OPEN for ${this.name}`);
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (err) {
this.onFailure(err);
throw err;
}
}
private onSuccess(): void {
if (this.state === 'HALF_OPEN') {
this.halfOpenSuccessCount++;
if (this.halfOpenSuccessCount >= this.options.halfOpenSuccessThreshold) {
this.state = 'CLOSED';
this.failureCount = 0;
this.halfOpenSuccessCount = 0;
logger.info({ service: this.name }, 'Circuit breaker: HALF_OPEN → CLOSED');
}
} else {
this.failureCount = 0;
}
}
private onFailure(err: unknown): void {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.state === 'HALF_OPEN') {
this.state = 'OPEN';
this.halfOpenSuccessCount = 0;
} else if (this.failureCount >= this.options.failureThreshold) {
this.state = 'OPEN';
logger.error({ service: this.name, failureCount: this.failureCount }, 'Circuit breaker: CLOSED → OPEN');
}
}
}
// Retry with exponential backoff
async function withRetry<T>(fn: () => Promise<T>, options = { maxAttempts: 3, baseDelayMs: 100, maxDelayMs: 5000 }): Promise<T> {
let lastError: Error;
for (let attempt = 0; attempt < options.maxAttempts; attempt++) {
try {
return await fn();
} catch (err) {
lastError = err as Error;
if (err instanceof HttpError && err.status >= 400 && err.status < 500) throw err; // Don't retry 4xx
if (attempt < options.maxAttempts - 1) {
const delay = Math.min(options.baseDelayMs * Math.pow(2, attempt), options.maxDelayMs);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError!;
}
// Resilient client: Circuit Breaker + Retry + Timeout
export class ResilientClient {
private circuitBreakers = new Map<string, CircuitBreaker>();
async get<T>(serviceName: string, url: string, timeoutMs = 3000): Promise<T> {
const cb = this.circuitBreakers.get(serviceName) ?? new CircuitBreaker(serviceName);
this.circuitBreakers.set(serviceName, cb);
return cb.execute(() => withRetry(async () => {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const res = await fetch(url, { signal: controller.signal, headers: { 'X-Trace-ID': getCurrentTraceId() } });
if (!res.ok) throw new HttpError(res.status, await res.text());
return res.json() as Promise<T>;
} finally {
clearTimeout(timeout);
}
}));
}
}
Summary
Design Microservice Communication with Claude Code:
- CLAUDE.md — document Circuit Breaker requirement, no retry on 4xx, 3s timeout
- Circuit Breaker — block calls after consecutive failures (prevent Cascade Failure)
- HALF_OPEN state — test calls to gradually recover
- Fallback — respond from cache when Circuit Breaker is OPEN
Review microservice designs with **Code Review Pack (¥980)* using /code-review at prompt-works.jp*
myouga (@myougatheaxo) — Axolotl VTuber.
Top comments (0)