logto-auth-node-sdk
Version:
A comprehensive Logto authentication client library with circuit breaker pattern support
90 lines (89 loc) • 3.54 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CircuitBreaker = void 0;
const circuit_breaker_types_1 = require("./types/circuit-breaker-types");
class CircuitBreaker {
constructor(defaultOptions = {
failureThreshold: 5,
resetTimeout: 30000,
halfOpenRetries: 2,
}) {
this.defaultOptions = defaultOptions;
this.circuits = new Map();
}
initCircuit(name, options) {
const circuitOptions = { ...this.defaultOptions, ...options };
this.circuits.set(name, {
name,
state: circuit_breaker_types_1.CircuitState.CLOSED,
failureCount: 0,
lastFailureTime: 0,
halfOpenRetries: 0,
options: circuitOptions,
});
}
async execute(circuitName, operation) {
const circuit = this.circuits.get(circuitName);
if (!circuit) {
// If circuit doesn't exist, create it with default options
this.initCircuit(circuitName);
return this.execute(circuitName, operation);
}
// Check if circuit should transition from OPEN to HALF_OPEN
if (circuit.state === circuit_breaker_types_1.CircuitState.OPEN) {
const timeSinceLastFailure = Date.now() - circuit.lastFailureTime;
if (timeSinceLastFailure >= circuit.options.resetTimeout) {
circuit.state = circuit_breaker_types_1.CircuitState.HALF_OPEN;
circuit.halfOpenRetries = 0;
}
else {
throw new Error(`Circuit breaker '${circuitName}' is OPEN`);
}
}
// If circuit is HALF_OPEN, check retry limit
if (circuit.state === circuit_breaker_types_1.CircuitState.HALF_OPEN && circuit.halfOpenRetries >= circuit.options.halfOpenRetries) {
throw new Error(`Circuit breaker '${circuitName}' is HALF_OPEN and retry limit exceeded`);
}
try {
const result = await operation();
// Success - reset circuit if it was HALF_OPEN or CLOSED
if (circuit.state === circuit_breaker_types_1.CircuitState.HALF_OPEN) {
circuit.state = circuit_breaker_types_1.CircuitState.CLOSED;
circuit.failureCount = 0;
circuit.halfOpenRetries = 0;
}
return result;
}
catch (error) {
circuit.failureCount++;
circuit.lastFailureTime = Date.now();
if (circuit.state === circuit_breaker_types_1.CircuitState.HALF_OPEN) {
circuit.halfOpenRetries++;
circuit.state = circuit_breaker_types_1.CircuitState.OPEN;
}
else if (circuit.failureCount >= circuit.options.failureThreshold) {
circuit.state = circuit_breaker_types_1.CircuitState.OPEN;
}
throw error;
}
}
getCircuitState(circuitName) {
return this.circuits.get(circuitName)?.state;
}
getCircuitInfo(circuitName) {
return this.circuits.get(circuitName);
}
getAllCircuits() {
return new Map(this.circuits);
}
resetCircuit(circuitName) {
const circuit = this.circuits.get(circuitName);
if (circuit) {
circuit.state = circuit_breaker_types_1.CircuitState.CLOSED;
circuit.failureCount = 0;
circuit.halfOpenRetries = 0;
circuit.lastFailureTime = 0;
}
}
}
exports.CircuitBreaker = CircuitBreaker;