UNPKG

durable-utils

Version:

Utilities for Cloudflare Durable Objects and Workers, including SQL migrations, sharding and retry utilities, and more.

64 lines (63 loc) 1.7 kB
// src/retries.ts function jitterBackoff(attempt, baseDelayMs, maxDelayMs) { const attemptUpperBoundMs = Math.min(2 ** attempt * baseDelayMs, maxDelayMs); return Math.floor(Math.random() * attemptUpperBoundMs); } async function tryN(n, fn, optionsOrFunction, optionsOld) { if (n <= 0) { throw new Error("n must be greater than 0"); } n = Math.floor(n); let options; if (typeof optionsOrFunction !== "function") { options = optionsOrFunction ?? {}; } else { options = { ...optionsOld, isRetryable: optionsOrFunction }; } return await tryWhile( fn, (err, nextAttempt) => { return nextAttempt <= n && (options.isRetryable?.(err, nextAttempt) ?? true); }, options ); } async function tryWhile(fn, isRetryable, options) { const baseDelayMs = Math.floor(options?.baseDelayMs ?? 100); const maxDelayMs = Math.floor(options?.maxDelayMs ?? 3e3); if (baseDelayMs <= 0 || maxDelayMs <= 0) { throw new Error("baseDelayMs and maxDelayMs must be greater than 0"); } if (baseDelayMs >= maxDelayMs) { throw new Error("baseDelayMs must be less than maxDelayMs"); } let attempt = 1; while (true) { try { return await fn(attempt); } catch (err) { if (options?.verbose) { console.info({ message: "tryWhile", attempt, error: String(err), errorProps: err }); } attempt += 1; if (!isRetryable(err, attempt)) { throw err; } const delay = jitterBackoff(attempt, baseDelayMs, maxDelayMs); await new Promise((resolve) => setTimeout(resolve, delay)); } } } export { jitterBackoff, tryN, tryWhile };