UNPKG

@iota-big3/sdk-gateway

Version:

Universal API Gateway with protocol translation, intelligent routing, rate limiting, health checking, and caching

149 lines 3.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CircuitBreaker = void 0; const events_1 = require("events"); class CircuitBreaker extends events_1.EventEmitter { constructor(config) { super(); this.state = 'CLOSED'; this.failures = 0; this.successes = 0; this.isEnabled = true; this.config = { ...config, failureThreshold: config.failureThreshold ?? 5, recoveryTimeout: config.recoveryTimeout ?? 30000, monitoringPeriod: config.monitoringPeriod ?? 60000 }; } async execute(fn) { if (!this.isEnabled) { return fn(); } if (this.state === 'OPEN') { if (this.shouldAttemptReset()) { this.state = 'HALF_OPEN'; this.emit('state:changed', { state: this.state, timestamp: Date.now() }); } else { throw new Error('Circuit breaker is OPEN'); } } try { const result = await fn(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } onSuccess() { if (!this.isEnabled) { return; } this.successes++; if (this.state === 'HALF_OPEN') { this.reset(); } } onFailure() { if (!this.isEnabled) { return; } this.failures++; this.lastFailure = Date.now(); if (this.failures >= this.config.failureThreshold) { this.trip(); } } shouldAttemptReset() { if (!this.nextAttempt) { return false; } return Date.now() >= this.nextAttempt; } trip() { if (!this.isEnabled) { return; } this.state = 'OPEN'; this.nextAttempt = Date.now() + this.config.recoveryTimeout; this.emit('circuit:opened', { failures: this.failures, timestamp: Date.now() }); this.emit('state:changed', { state: this.state, timestamp: Date.now() }); } reset() { if (!this.isEnabled) { return; } this.state = 'CLOSED'; this.failures = 0; this.successes = 0; this.lastFailure = undefined; this.nextAttempt = undefined; this.emit('circuit:closed', { timestamp: Date.now() }); this.emit('state:changed', { state: this.state, timestamp: Date.now() }); } getMetrics() { if (!this.isEnabled) { return { state: 'CLOSED', failures: 0, successes: 0 }; } return { state: this.state, failures: this.failures, successes: this.successes, lastFailure: this.lastFailure, nextAttempt: this.nextAttempt }; } getState() { return this.state; } isCircuitOpen() { return this.state === 'OPEN'; } isCircuitClosed() { return this.state === 'CLOSED'; } isCircuitHalfOpen() { return this.state === 'HALF_OPEN'; } enable() { this.isEnabled = true; } disable() { this.isEnabled = false; } forceOpen() { this.state = 'OPEN'; this.nextAttempt = Date.now() + this.config.recoveryTimeout; this.emit('state:changed', { state: this.state, timestamp: Date.now() }); } forceClose() { this.reset(); } forceClear() { this.failures = 0; this.successes = 0; this.lastFailure = undefined; this.nextAttempt = undefined; } } exports.CircuitBreaker = CircuitBreaker; //# sourceMappingURL=circuit-breaker.js.map