UNPKG

@ai-capabilities-suite/mcp-debugger-core

Version:

Core debugging engine for Node.js and TypeScript applications. Provides Inspector Protocol integration, breakpoint management, variable inspection, execution control, profiling, hang detection, and source map support.

230 lines 6.93 kB
"use strict"; /** * Circuit Breaker Pattern Implementation * Prevents cascading failures by failing fast when a service is unhealthy */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CircuitBreakerManager = exports.CircuitBreaker = exports.CircuitState = void 0; var CircuitState; (function (CircuitState) { CircuitState["CLOSED"] = "CLOSED"; CircuitState["OPEN"] = "OPEN"; CircuitState["HALF_OPEN"] = "HALF_OPEN"; })(CircuitState || (exports.CircuitState = CircuitState = {})); class CircuitBreaker { constructor(name, config) { this.name = name; this.config = config; this.state = CircuitState.CLOSED; this.failures = 0; this.successes = 0; this.consecutiveFailures = 0; this.consecutiveSuccesses = 0; } /** * Execute an operation through the circuit breaker * @param operation The async operation to execute * @returns The result of the operation * @throws Error if circuit is open or operation fails */ async execute(operation) { // Check if circuit is open if (this.state === CircuitState.OPEN) { throw new Error(`Circuit breaker '${this.name}' is OPEN. Failing fast.`); } try { // Execute with timeout if configured const result = this.config.timeout ? await this.executeWithTimeout(operation, this.config.timeout) : await operation(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } /** * Execute operation with timeout */ async executeWithTimeout(operation, timeout) { return Promise.race([ operation(), new Promise((_, reject) => setTimeout(() => reject(new Error(`Operation timed out after ${timeout}ms`)), timeout)), ]); } /** * Handle successful operation */ onSuccess() { this.successes++; this.consecutiveSuccesses++; this.consecutiveFailures = 0; this.lastSuccessTime = Date.now(); // If in half-open state and reached success threshold, close circuit if (this.state === CircuitState.HALF_OPEN && this.consecutiveSuccesses >= this.config.successThreshold) { this.closeCircuit(); } } /** * Handle failed operation */ onFailure() { this.failures++; this.consecutiveFailures++; this.consecutiveSuccesses = 0; this.lastFailureTime = Date.now(); // If reached failure threshold, open circuit if (this.consecutiveFailures >= this.config.failureThreshold) { this.openCircuit(); } } /** * Open the circuit (start failing fast) */ openCircuit() { if (this.state === CircuitState.OPEN) { return; } this.state = CircuitState.OPEN; console.warn(`Circuit breaker '${this.name}' opened after ${this.consecutiveFailures} consecutive failures`); // Schedule automatic transition to half-open this.resetTimer = setTimeout(() => { this.halfOpenCircuit(); }, this.config.resetTimeout); } /** * Transition to half-open state (test if service recovered) */ halfOpenCircuit() { this.state = CircuitState.HALF_OPEN; this.consecutiveSuccesses = 0; console.log(`Circuit breaker '${this.name}' transitioned to HALF_OPEN, testing recovery`); } /** * Close the circuit (resume normal operation) */ closeCircuit() { this.state = CircuitState.CLOSED; this.consecutiveFailures = 0; console.log(`Circuit breaker '${this.name}' closed, resuming normal operation`); if (this.resetTimer) { clearTimeout(this.resetTimer); this.resetTimer = undefined; } } /** * Manually reset the circuit breaker */ reset() { this.state = CircuitState.CLOSED; this.failures = 0; this.successes = 0; this.consecutiveFailures = 0; this.consecutiveSuccesses = 0; this.lastFailureTime = undefined; this.lastSuccessTime = undefined; if (this.resetTimer) { clearTimeout(this.resetTimer); this.resetTimer = undefined; } console.log(`Circuit breaker '${this.name}' manually reset`); } /** * Get current circuit breaker statistics */ getStats() { return { state: this.state, failures: this.failures, successes: this.successes, consecutiveFailures: this.consecutiveFailures, consecutiveSuccesses: this.consecutiveSuccesses, lastFailureTime: this.lastFailureTime, lastSuccessTime: this.lastSuccessTime, }; } /** * Get current circuit state */ getState() { return this.state; } /** * Check if circuit is open */ isOpen() { return this.state === CircuitState.OPEN; } /** * Check if circuit is closed */ isClosed() { return this.state === CircuitState.CLOSED; } /** * Check if circuit is half-open */ isHalfOpen() { return this.state === CircuitState.HALF_OPEN; } } exports.CircuitBreaker = CircuitBreaker; /** * Circuit Breaker Manager * Manages multiple circuit breakers for different operations */ class CircuitBreakerManager { constructor() { this.breakers = new Map(); } /** * Create or get a circuit breaker * @param name Circuit breaker name * @param config Circuit breaker configuration * @returns The circuit breaker instance */ getOrCreate(name, config) { if (!this.breakers.has(name)) { this.breakers.set(name, new CircuitBreaker(name, config)); } return this.breakers.get(name); } /** * Get a circuit breaker by name * @param name Circuit breaker name * @returns The circuit breaker or undefined */ get(name) { return this.breakers.get(name); } /** * Get all circuit breakers * @returns Map of all circuit breakers */ getAll() { return new Map(this.breakers); } /** * Reset all circuit breakers */ resetAll() { for (const breaker of this.breakers.values()) { breaker.reset(); } } /** * Get statistics for all circuit breakers */ getAllStats() { const stats = new Map(); for (const [name, breaker] of this.breakers.entries()) { stats.set(name, breaker.getStats()); } return stats; } } exports.CircuitBreakerManager = CircuitBreakerManager; //# sourceMappingURL=circuit-breaker.js.map