/** * 熔断器 - 供应商级别的故障隔离 * * 状态机: CLOSED → (N次连续失败) → OPEN → (冷却期过后) → HALF_OPEN → (成功) → CLOSED * * 使用方式: * const breaker = new CircuitBreaker({ name: 'minimax', failureThreshold: 3, cooldownMs: 30000 }); * try { * await breaker.call(async () => { ... }); * } catch (e) { * // 熔断开启或调用失败 * } */ export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN'; export interface CircuitBreakerConfig { name: string; failureThreshold?: number; // 连续失败多少次后熔断,默认 3 cooldownMs?: number; // 熔断冷却时间,默认 30000ms successThreshold?: number; // HALF_OPEN 状态下需要连续成功多少次才恢复,默认 2 } export class CircuitBreaker { readonly name: string; private failureThreshold: number; private cooldownMs: number; private successThreshold: number; private state: CircuitState = 'CLOSED'; private failureCount = 0; private successCount = 0; private openedAt = 0; constructor(config: CircuitBreakerConfig) { this.name = config.name; this.failureThreshold = config.failureThreshold ?? 3; this.cooldownMs = config.cooldownMs ?? 30000; this.successThreshold = config.successThreshold ?? 2; } getState(): CircuitState { // 如果 OPEN 且冷却期已过,自动进入 HALF_OPEN if (this.state === 'OPEN' && Date.now() - this.openedAt >= this.cooldownMs) { this.state = 'HALF_OPEN'; this.failureCount = 0; this.successCount = 0; console.log(`[熔断器] ${this.name}: OPEN → HALF_OPEN(冷却期已过)`); } return this.state; } isOpen(): boolean { return this.getState() === 'OPEN'; } /** * 执行受保护的操作 * 返回操作成功的结果,抛出 CircuitBreakerOpenError 或原始错误 */ async call(fn: () => Promise): Promise { const currentState = this.getState(); if (currentState === 'OPEN') { const remainingMs = this.cooldownMs - (Date.now() - this.openedAt); throw new CircuitBreakerOpenError(this.name, remainingMs); } try { const result = await fn(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } private onSuccess(): void { if (this.state === 'HALF_OPEN') { this.successCount++; if (this.successCount >= this.successThreshold) { this.state = 'CLOSED'; this.failureCount = 0; this.successCount = 0; console.log(`[熔断器] ${this.name}: HALF_OPEN → CLOSED(恢复)`); } } else { // CLOSED 状态,重置失败计数 this.failureCount = 0; } } private onFailure(): void { this.failureCount++; this.successCount = 0; if (this.state === 'HALF_OPEN' || (this.state === 'CLOSED' && this.failureCount >= this.failureThreshold)) { this.state = 'OPEN'; this.openedAt = Date.now(); console.log(`[熔断器] ${this.name}: → OPEN(连续失败 ${this.failureCount} 次,冷却 ${this.cooldownMs}ms)`); } } /** 手动重置 */ reset(): void { this.state = 'CLOSED'; this.failureCount = 0; this.successCount = 0; this.openedAt = 0; } } export class CircuitBreakerOpenError extends Error { public readonly breakerName: string; public readonly remainingMs: number; constructor(name: string, remainingMs: number) { super(`[${name}] 熔断器已开启,剩余冷却时间 ${Math.ceil(remainingMs / 1000)}s`); this.name = 'CircuitBreakerOpenError'; this.breakerName = name; this.remainingMs = remainingMs; } }