import { warn } from "./log"; export async function delay(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } export function exponentialBackoffDelay(currentFailureCount: number, minDelay: number, maxDelay: number, maxFailureCount: number) { let maxDelayRet = minDelay + ((maxDelay - minDelay) / maxFailureCount) * Math.max(currentFailureCount, maxFailureCount); return Math.round(Math.random() * maxDelayRet); } export type BackoffFunc = (callback: () => Promise) => Promise; export function createBackoff( opts?: { onError?: (e: any, failuresCount: number) => void, minDelay?: number, maxDelay?: number, maxFailureCount?: number }): BackoffFunc { return async (callback: () => Promise): Promise => { let currentFailureCount = 0; const minDelay = opts && opts.minDelay !== undefined ? opts.minDelay : 250; const maxDelay = opts && opts.maxDelay !== undefined ? opts.maxDelay : 1000; const maxFailureCount = opts && opts.maxFailureCount !== undefined ? opts.maxFailureCount : 50; while (true) { try { return await callback(); } catch (e) { if (currentFailureCount < maxFailureCount) { currentFailureCount++; } if (opts && opts.onError) { opts.onError(e, currentFailureCount); } let waitForRequest = exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount); await delay(waitForRequest); } } }; } export let backoff = createBackoff({ onError: (e) => { warn(e); } });