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.

125 lines 4.79 kB
"use strict"; /** * Retry Handler with Exponential Backoff * Implements retry logic for transient failures */ Object.defineProperty(exports, "__esModule", { value: true }); exports.RetryHandler = void 0; exports.Retryable = Retryable; class RetryHandler { /** * Execute an operation with retry logic * @param operation The async operation to execute * @param config Retry configuration * @returns The result of the operation * @throws The last error if all retries fail */ static async execute(operation, config = {}) { const fullConfig = { ...RetryHandler.DEFAULT_CONFIG, ...config }; let lastError; let attempt = 0; let totalDelay = 0; while (attempt < fullConfig.maxAttempts) { try { const result = await operation(); return result; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); attempt++; // Check if error is retryable if (fullConfig.isRetryable && !fullConfig.isRetryable(lastError)) { throw lastError; } // If this was the last attempt, throw the error if (attempt >= fullConfig.maxAttempts) { throw lastError; } // Calculate delay with exponential backoff and jitter const delay = RetryHandler.calculateDelay(attempt, fullConfig.initialDelay, fullConfig.maxDelay, fullConfig.backoffMultiplier, fullConfig.jitter); totalDelay += delay; console.log(`Retry attempt ${attempt}/${fullConfig.maxAttempts} after ${delay}ms delay. Error: ${lastError.message}`); // Wait before retrying await RetryHandler.sleep(delay); } } // This should never be reached, but TypeScript needs it throw lastError || new Error('All retry attempts failed'); } /** * Calculate delay with exponential backoff and jitter */ static calculateDelay(attempt, initialDelay, maxDelay, multiplier, jitter) { // Calculate exponential backoff const exponentialDelay = initialDelay * Math.pow(multiplier, attempt - 1); // Cap at max delay const cappedDelay = Math.min(exponentialDelay, maxDelay); // Add jitter to prevent thundering herd const jitterAmount = cappedDelay * jitter * (Math.random() * 2 - 1); const finalDelay = Math.max(0, cappedDelay + jitterAmount); return Math.floor(finalDelay); } /** * Sleep for specified milliseconds */ static sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * Execute with retry and return stats */ static async executeWithStats(operation, config = {}) { const fullConfig = { ...RetryHandler.DEFAULT_CONFIG, ...config }; let lastError; let attempt = 0; let totalDelay = 0; while (attempt < fullConfig.maxAttempts) { try { const result = await operation(); return { result, stats: { attempts: attempt + 1, totalDelay, success: true, }, }; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); attempt++; if (fullConfig.isRetryable && !fullConfig.isRetryable(lastError)) { throw lastError; } if (attempt >= fullConfig.maxAttempts) { throw lastError; } const delay = RetryHandler.calculateDelay(attempt, fullConfig.initialDelay, fullConfig.maxDelay, fullConfig.backoffMultiplier, fullConfig.jitter); totalDelay += delay; await RetryHandler.sleep(delay); } } throw lastError || new Error('All retry attempts failed'); } } exports.RetryHandler = RetryHandler; RetryHandler.DEFAULT_CONFIG = { maxAttempts: 3, initialDelay: 100, maxDelay: 10000, backoffMultiplier: 2, jitter: 0.1, }; /** * Decorator for adding retry logic to methods */ function Retryable(config = {}) { return function (target, propertyKey, descriptor) { const originalMethod = descriptor.value; descriptor.value = async function (...args) { return RetryHandler.execute(() => originalMethod.apply(this, args), config); }; return descriptor; }; } //# sourceMappingURL=retry-handler.js.map