UNPKG

@shopana/ga

Version:

Type-safe Google Analytics 4 (GA4) tracking library for React and Next.js with ecommerce support, event batching, and SSR compatibility

76 lines 2.72 kB
import { DEFAULT_MAX_RETRY_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_RETRY_JITTER_RATIO, } from './constants'; const ABORT_ERROR_MESSAGE = 'RetryController has been aborted'; export class RetryController { constructor(options = {}) { this.options = options; this.aborted = false; this.activeDelays = new Set(); } async execute(operation) { if (this.aborted) { throw this.createAbortError(); } const maxRetries = this.options.maxAttempts ?? DEFAULT_MAX_RETRY_ATTEMPTS; const baseDelay = this.options.delayMs ?? DEFAULT_RETRY_DELAY_MS; const jitterRatio = this.options.jitterRatio ?? DEFAULT_RETRY_JITTER_RATIO; let attempt = 0; while (attempt <= maxRetries) { if (this.aborted) { throw this.createAbortError(); } try { return await operation(); } catch (error) { if (attempt >= maxRetries) { throw error; } attempt += 1; const delay = baseDelay * Math.pow(2, attempt - 1); const jitter = delay * jitterRatio * Math.random(); if (this.aborted) { throw this.createAbortError(); } await new Promise((resolve, reject) => { const delayEntry = { timer: undefined, reject: (error) => reject(error), }; delayEntry.timer = setTimeout(() => { this.clearDelay(delayEntry); if (this.aborted) { reject(this.createAbortError()); } else { resolve(); } }, delay + jitter); this.activeDelays.add(delayEntry); if (this.aborted) { this.rejectDelay(delayEntry); } }); } } throw new Error('Max retry attempts reached'); } abort() { this.aborted = true; for (const delay of this.activeDelays) { this.rejectDelay(delay); } this.activeDelays.clear(); } createAbortError() { return new Error(ABORT_ERROR_MESSAGE); } clearDelay(delay) { clearTimeout(delay.timer); this.activeDelays.delete(delay); } rejectDelay(delay) { this.clearDelay(delay); delay.reject(this.createAbortError()); } } //# sourceMappingURL=RetryController.js.map