circuit-breaker

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Circuit Breaker Pattern

断路器模式(Circuit Breaker Pattern)

Prevent cascade failures by failing fast when a service is unhealthy.
当服务状态异常时,通过快速失败来防止级联故障。

When to Use This Skill

适用场景

  • Adding resilience to external API calls
  • Protecting against slow or failing downstream services
  • Implementing graceful degradation
  • Building fault-tolerant microservices
  • 为外部API调用添加弹性
  • 防范下游服务响应缓慢或故障
  • 实现优雅降级
  • 构建容错微服务

Core Concepts

核心概念

A circuit breaker has three states:
  1. CLOSED: Normal operation, requests pass through
  2. OPEN: Service is failing, requests fail immediately
  3. HALF_OPEN: Testing if service recovered
断路器包含三种状态:
  1. CLOSED(闭合状态):正常运行,请求正常通过
  2. OPEN(断开状态):服务故障,请求立即失败
  3. HALF_OPEN(半开状态):测试服务是否已恢复

TypeScript Implementation

TypeScript 实现

typescript
// circuit-breaker.ts
type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';

interface CircuitBreakerConfig {
  failureThreshold: number;      // Failures before opening
  successThreshold: number;      // Successes to close from half-open
  timeout: number;               // Ms before trying half-open
  fallback?: () => Promise<any>; // Optional fallback
}

class CircuitBreaker {
  private state: CircuitState = 'CLOSED';
  private failures = 0;
  private successes = 0;
  private lastFailureTime = 0;
  private readonly config: CircuitBreakerConfig;

  constructor(config: Partial<CircuitBreakerConfig> = {}) {
    this.config = {
      failureThreshold: 5,
      successThreshold: 2,
      timeout: 30000,
      ...config,
    };
  }

  async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime >= this.config.timeout) {
        this.state = 'HALF_OPEN';
      } else {
        if (this.config.fallback) {
          return this.config.fallback();
        }
        throw new CircuitOpenError('Circuit is OPEN');
      }
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private onSuccess(): void {
    this.failures = 0;
    if (this.state === 'HALF_OPEN') {
      this.successes++;
      if (this.successes >= this.config.successThreshold) {
        this.state = 'CLOSED';
        this.successes = 0;
      }
    }
  }

  private onFailure(): void {
    this.failures++;
    this.lastFailureTime = Date.now();
    if (this.failures >= this.config.failureThreshold) {
      this.state = 'OPEN';
    }
  }

  getState(): CircuitState {
    return this.state;
  }
}

class CircuitOpenError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'CircuitOpenError';
  }
}

export { CircuitBreaker, CircuitBreakerConfig, CircuitOpenError };
typescript
// circuit-breaker.ts
type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';

interface CircuitBreakerConfig {
  failureThreshold: number;      // Failures before opening
  successThreshold: number;      // Successes to close from half-open
  timeout: number;               // Ms before trying half-open
  fallback?: () => Promise<any>; // Optional fallback
}

class CircuitBreaker {
  private state: CircuitState = 'CLOSED';
  private failures = 0;
  private successes = 0;
  private lastFailureTime = 0;
  private readonly config: CircuitBreakerConfig;

  constructor(config: Partial<CircuitBreakerConfig> = {}) {
    this.config = {
      failureThreshold: 5,
      successThreshold: 2,
      timeout: 30000,
      ...config,
    };
  }

  async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime >= this.config.timeout) {
        this.state = 'HALF_OPEN';
      } else {
        if (this.config.fallback) {
          return this.config.fallback();
        }
        throw new CircuitOpenError('Circuit is OPEN');
      }
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private onSuccess(): void {
    this.failures = 0;
    if (this.state === 'HALF_OPEN') {
      this.successes++;
      if (this.successes >= this.config.successThreshold) {
        this.state = 'CLOSED';
        this.successes = 0;
      }
    }
  }

  private onFailure(): void {
    this.failures++;
    this.lastFailureTime = Date.now();
    if (this.failures >= this.config.failureThreshold) {
      this.state = 'OPEN';
    }
  }

  getState(): CircuitState {
    return this.state;
  }
}

class CircuitOpenError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'CircuitOpenError';
  }
}

export { CircuitBreaker, CircuitBreakerConfig, CircuitOpenError };

Python Implementation

Python 实现

python
undefined
python
undefined

circuit_breaker.py

circuit_breaker.py

import time from enum import Enum from typing import Callable, TypeVar, Optional from functools import wraps
T = TypeVar('T')
class CircuitState(Enum): CLOSED = "closed" OPEN = "open" HALF_OPEN = "half_open"
class CircuitOpenError(Exception): pass
class CircuitBreaker: def init( self, failure_threshold: int = 5, success_threshold: int = 2, timeout: float = 30.0, fallback: Optional[Callable] = None, ): self.failure_threshold = failure_threshold self.success_threshold = success_threshold self.timeout = timeout self.fallback = fallback
    self._state = CircuitState.CLOSED
    self._failures = 0
    self._successes = 0
    self._last_failure_time = 0.0

@property
def state(self) -> CircuitState:
    return self._state

def __call__(self, fn: Callable[..., T]) -> Callable[..., T]:
    @wraps(fn)
    def wrapper(*args, **kwargs) -> T:
        return self.execute(lambda: fn(*args, **kwargs))
    return wrapper

def execute(self, fn: Callable[[], T]) -> T:
    if self._state == CircuitState.OPEN:
        if time.time() - self._last_failure_time >= self.timeout:
            self._state = CircuitState.HALF_OPEN
        else:
            if self.fallback:
                return self.fallback()
            raise CircuitOpenError("Circuit is OPEN")

    try:
        result = fn()
        self._on_success()
        return result
    except Exception as e:
        self._on_failure()
        raise

def _on_success(self) -> None:
    self._failures = 0
    if self._state == CircuitState.HALF_OPEN:
        self._successes += 1
        if self._successes >= self.success_threshold:
            self._state = CircuitState.CLOSED
            self._successes = 0

def _on_failure(self) -> None:
    self._failures += 1
    self._last_failure_time = time.time()
    if self._failures >= self.failure_threshold:
        self._state = CircuitState.OPEN
undefined
import time from enum import Enum from typing import Callable, TypeVar, Optional from functools import wraps
T = TypeVar('T')
class CircuitState(Enum): CLOSED = "closed" OPEN = "open" HALF_OPEN = "half_open"
class CircuitOpenError(Exception): pass
class CircuitBreaker: def init( self, failure_threshold: int = 5, success_threshold: int = 2, timeout: float = 30.0, fallback: Optional[Callable] = None, ): self.failure_threshold = failure_threshold self.success_threshold = success_threshold self.timeout = timeout self.fallback = fallback
    self._state = CircuitState.CLOSED
    self._failures = 0
    self._successes = 0
    self._last_failure_time = 0.0

@property
def state(self) -> CircuitState:
    return self._state

def __call__(self, fn: Callable[..., T]) -> Callable[..., T]:
    @wraps(fn)
    def wrapper(*args, **kwargs) -> T:
        return self.execute(lambda: fn(*args, **kwargs))
    return wrapper

def execute(self, fn: Callable[[], T]) -> T:
    if self._state == CircuitState.OPEN:
        if time.time() - self._last_failure_time >= self.timeout:
            self._state = CircuitState.HALF_OPEN
        else:
            if self.fallback:
                return self.fallback()
            raise CircuitOpenError("Circuit is OPEN")

    try:
        result = fn()
        self._on_success()
        return result
    except Exception as e:
        self._on_failure()
        raise

def _on_success(self) -> None:
    self._failures = 0
    if self._state == CircuitState.HALF_OPEN:
        self._successes += 1
        if self._successes >= self.success_threshold:
            self._state = CircuitState.CLOSED
            self._successes = 0

def _on_failure(self) -> None:
    self._failures += 1
    self._last_failure_time = time.time()
    if self._failures >= self.failure_threshold:
        self._state = CircuitState.OPEN
undefined

Usage Examples

使用示例

TypeScript with API Client

TypeScript 结合API客户端

typescript
const paymentCircuit = new CircuitBreaker({
  failureThreshold: 3,
  timeout: 60000,
  fallback: async () => ({ status: 'pending', message: 'Payment service unavailable' }),
});

async function processPayment(amount: number) {
  return paymentCircuit.execute(async () => {
    const response = await fetch('https://api.stripe.com/v1/charges', {
      method: 'POST',
      body: JSON.stringify({ amount }),
    });
    if (!response.ok) throw new Error('Payment failed');
    return response.json();
  });
}
typescript
const paymentCircuit = new CircuitBreaker({
  failureThreshold: 3,
  timeout: 60000,
  fallback: async () => ({ status: 'pending', message: 'Payment service unavailable' }),
});

async function processPayment(amount: number) {
  return paymentCircuit.execute(async () => {
    const response = await fetch('https://api.stripe.com/v1/charges', {
      method: 'POST',
      body: JSON.stringify({ amount }),
    });
    if (!response.ok) throw new Error('Payment failed');
    return response.json();
  });
}

Python Decorator Style

Python 装饰器风格

python
circuit = CircuitBreaker(failure_threshold=3, timeout=60)

@circuit
def call_external_api(endpoint: str) -> dict:
    response = requests.get(endpoint, timeout=5)
    response.raise_for_status()
    return response.json()
python
circuit = CircuitBreaker(failure_threshold=3, timeout=60)

@circuit
def call_external_api(endpoint: str) -> dict:
    response = requests.get(endpoint, timeout=5)
    response.raise_for_status()
    return response.json()

Integration with Observability

与可观测性集成

Add metrics to track circuit state:
typescript
// With Prometheus
import { Gauge, Counter } from 'prom-client';

const circuitState = new Gauge({
  name: 'circuit_breaker_state',
  help: 'Current circuit breaker state (0=closed, 1=open, 2=half-open)',
  labelNames: ['service'],
});

const circuitTrips = new Counter({
  name: 'circuit_breaker_trips_total',
  help: 'Total circuit breaker trips',
  labelNames: ['service'],
});
添加指标以跟踪断路器状态:
typescript
// With Prometheus
import { Gauge, Counter } from 'prom-client';

const circuitState = new Gauge({
  name: 'circuit_breaker_state',
  help: 'Current circuit breaker state (0=closed, 1=open, 2=half-open)',
  labelNames: ['service'],
});

const circuitTrips = new Counter({
  name: 'circuit_breaker_trips_total',
  help: 'Total circuit breaker trips',
  labelNames: ['service'],
});

Best Practices

最佳实践

  1. Tune thresholds per service: Critical services need lower thresholds
  2. Always provide fallbacks: Graceful degradation > hard failures
  3. Monitor circuit state: Alert when circuits open frequently
  4. Use separate circuits: One per external dependency
  5. Consider bulkheads: Combine with connection pooling
  1. 为每个服务调整阈值:核心服务需要更低的阈值
  2. 始终提供降级方案:优雅降级优于直接故障
  3. 监控断路器状态:当断路器频繁断开时触发告警
  4. 使用独立的断路器:每个外部依赖对应一个断路器
  5. 考虑舱壁模式:与连接池结合使用

Common Mistakes

常见错误

  • Setting timeout too short (service never recovers)
  • Sharing circuits across unrelated services
  • Not handling CircuitOpenError in calling code
  • Forgetting to add observability
  • 超时时间设置过短(服务无法恢复)
  • 在不相关的服务间共享断路器
  • 调用代码中未处理CircuitOpenError
  • 忘记添加可观测性

Related Patterns

相关模式

  • Retry with exponential backoff
  • Bulkhead isolation
  • Timeout pattern
  • Fallback pattern
  • 指数退避重试
  • 舱壁隔离
  • 超时模式
  • 降级模式