Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 1x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x 119x 7x 7x 7x 7x 7x 119x 119x 78x 25x 25x 78x 69x 69x 2x 2x 2x 67x 67x 5x 5x 69x 62x 62x 62x 69x 78x 5x 3x 3x 1x 1x 1x 1x 1x 5x 2x 2x 5x 78x 63x 63x 63x 20x 20x 20x 20x 63x 78x 3x 3x 3x 3x 3x 78x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x | /**
* 熔断器 - 供应商级别的故障隔离
*
* 状态机: 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<T>(fn: () => Promise<T>): Promise<T> {
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;
}
}
|