UNPKG

qapinterface

Version:

Comprehensive API utilities for Node.js applications including authentication, security, request processing, and response handling with zero external dependencies

78 lines (74 loc) 3.27 kB
/** * Service Connection Retry Handler with Exponential Backoff * * SINGLE RESPONSIBILITY: Handle service connection retries with resilience patterns ONLY * * RESILIENCE STRATEGY: * This module implements a robust retry mechanism essential for microservice architectures * where external dependencies may be temporarily unavailable. The retry logic includes: * - Exponential backoff to reduce load on struggling services * - Configurable retry limits to prevent infinite loops * - Proper error propagation for circuit breaker patterns * - Resource cleanup to prevent connection leaks * * WHY EXPONENTIAL BACKOFF: * Linear delays can create thundering herd problems where all clients retry simultaneously. * Exponential backoff spreads retry attempts over time, reducing load spikes and improving * the chances of successful reconnection as services recover. * * DESIGN DECISIONS: * - Function-based approach allows any connection logic (DB, HTTP, etc.) * - Promise-based for async/await compatibility * - Configuration object pattern for extensibility * - Fail-fast on final attempt to enable circuit breaker logic */ /** * Attempts service connection with configurable retry logic and exponential backoff. * * RETRY ALGORITHM: * 1. Execute connection function * 2. On failure, wait (attempt_number * 1000)ms before retry * 3. Repeat up to maxRetries times * 4. Throw final error if all attempts fail * * BACKOFF CALCULATION: * - Attempt 1: 1 second delay * - Attempt 2: 2 second delay * - Attempt 3: 3 second delay * - Linear progression prevents excessive delays while spreading load * * @param {Function} connectionFn - Async function that returns Promise for connection attempt * @param {object} [retryOptions={}] - Configuration for retry behavior * @param {number} [retryOptions.retries=3] - Maximum number of retry attempts * @returns {Promise<any>} Promise resolving to connectionFn result or rejecting with final error * @throws {Error} The final error after all retry attempts are exhausted */ async function connectWithRetry(connectionFn, retryOptions = {}) { // Configuration: Extract retry count with sensible default // 3 retries balances resilience with reasonable timeout duration const maxRetries = retryOptions.retries || 3; // Retry loop: Attempt connection up to maxRetries times for (let i = 0; i < maxRetries; i++) { try { // Connection attempt: Execute provided async function // Return immediately on success, preserving the connection result return await connectionFn(); } catch (error) { // Final attempt handling: Re-throw error if no retries remain // This preserves the original error context for upstream error handling if (i === maxRetries - 1) { throw error; } // Exponential backoff delay: Wait longer between each retry // Calculation: (attempt_number + 1) * 1000ms // - Attempt 0: 1000ms (1 second) // - Attempt 1: 2000ms (2 seconds) // - Attempt 2: 3000ms (3 seconds) // This prevents thundering herd and gives services time to recover await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } } module.exports = { connectWithRetry };