circuit-breaker
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCircuit 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:
- CLOSED: Normal operation, requests pass through
- OPEN: Service is failing, requests fail immediately
- HALF_OPEN: Testing if service recovered
断路器包含三种状态:
- CLOSED(闭合状态):正常运行,请求正常通过
- OPEN(断开状态):服务故障,请求立即失败
- 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
undefinedpython
undefinedcircuit_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.OPENundefinedimport 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.OPENundefinedUsage 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
最佳实践
- Tune thresholds per service: Critical services need lower thresholds
- Always provide fallbacks: Graceful degradation > hard failures
- Monitor circuit state: Alert when circuits open frequently
- Use separate circuits: One per external dependency
- Consider bulkheads: Combine with connection pooling
- 为每个服务调整阈值:核心服务需要更低的阈值
- 始终提供降级方案:优雅降级优于直接故障
- 监控断路器状态:当断路器频繁断开时触发告警
- 使用独立的断路器:每个外部依赖对应一个断路器
- 考虑舱壁模式:与连接池结合使用
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
- 指数退避重试
- 舱壁隔离
- 超时模式
- 降级模式