@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
JavaScript
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