UNPKG

logto-auth-node-sdk

Version:

A comprehensive Logto authentication client library with circuit breaker pattern support

90 lines (89 loc) 3.54 kB
"use strict"; 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;