@iota-big3/sdk-gateway
Version:
Universal API Gateway with protocol translation, intelligent routing, rate limiting, health checking, and caching
149 lines • 3.95 kB
JavaScript
"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