Communication Between Services

Lesson 8 of 10 · 24 min

x
80%

Resilience: Retries, Timeouts & Circuit Breakers

Networks fail. Services crash. Timeouts expire. Without resilience patterns, one slow dependency cascades into a system-wide outage — the classic cascading failure. Three patterns defend against this. Timeouts cap how long a caller waits. Retries re-attempt transient failures (network blip, 503) with exponential backoff and jitter so you do not hammer a recovering service. Circuit breakers stop calling a failing service entirely after a threshold of errors, giving it time to recover while the caller fails fast or returns a fallback. Together they turn "everything is down" into "this one feature is degraded."

Before
Fragile — retry storm on outage
async function getRecommendations(userId) {
  // Retries immediately, 100 times, no backoff
  for (let i = 0; i < 100; i++) {
    try {
      return await fetch('/recommendations/' + userId);
    } catch (e) { /* retry */ }
  }
}
After
Resilient — circuit breaker + backoff
const breaker = new CircuitBreaker(fetchRecommendations, {
  timeout: 3000,
  errorThresholdPercentage: 50,
  resetTimeout: 30000,
});

async function fetchRecommendations(userId) {
  return fetchWithRetry(
    `/recommendations/${userId}`,
    { retries: 3, backoff: 'exponential' }
  );
}

// After 50% failures → circuit opens → fail fast for 30s

Key Takeaway

Timeout every call, retry transient errors with backoff, and trip the circuit breaker before a sick dependency takes down your whole system.

PreviousNext Lesson