/** * Retry backoff strategies */ import type { TBackoffStrategy } from '../webrequest.types.js'; export interface IBackoffCalculator { calculate(attempt: number, initialDelay: number, maxDelay: number): number; } /** * Exponential backoff strategy * Delay increases exponentially: initialDelay * 2^attempt */ export class ExponentialBackoff implements IBackoffCalculator { calculate(attempt: number, initialDelay: number, maxDelay: number): number { const delay = initialDelay * Math.pow(2, attempt - 1); return Math.min(delay, maxDelay); } } /** * Linear backoff strategy * Delay increases linearly: initialDelay * attempt */ export class LinearBackoff implements IBackoffCalculator { calculate(attempt: number, initialDelay: number, maxDelay: number): number { const delay = initialDelay * attempt; return Math.min(delay, maxDelay); } } /** * Constant backoff strategy * Delay stays constant: initialDelay */ export class ConstantBackoff implements IBackoffCalculator { calculate(attempt: number, initialDelay: number, maxDelay: number): number { return Math.min(initialDelay, maxDelay); } } /** * Get backoff calculator for a given strategy */ export function getBackoffCalculator( strategy: TBackoffStrategy, ): IBackoffCalculator { switch (strategy) { case 'exponential': return new ExponentialBackoff(); case 'linear': return new LinearBackoff(); case 'constant': return new ConstantBackoff(); default: return new ExponentialBackoff(); } } /** * Add jitter to delay to prevent thundering herd */ export function addJitter(delay: number, jitterFactor: number = 0.1): number { const jitter = delay * jitterFactor * Math.random(); return delay + jitter; }