Helpers for automatic retrying of sketchy processes. Linear delay or exponential backoff. by @wellcaffeinated
Demo at: https://jsfiddle.net/gh/gist/library/pure/df1dc4bea62688c8f372d2b76b189d32
Helpers for automatic retrying of sketchy processes. Linear delay or exponential backoff. by @wellcaffeinated
Demo at: https://jsfiddle.net/gh/gist/library/pure/df1dc4bea62688c8f372d2b76b189d32
<pre id="log"></pre> |
// --- | |
// Helpers for automatic retrying of sketchy processes. | |
// Linear delay or exponential backoff | |
// Made by @wellcaffeinated | |
// No copyright | |
// --- | |
// Throw an instance of this in order to continue retrying | |
class Retry extends Error {} | |
// Use this to wrap a function that may fail. If the function | |
// throws an instance of Retry, it will be attempted again | |
// until it resolves or throws anything else | |
const withRetry = (fn, { | |
maxTries = false, | |
dt = 1000, | |
expBackoff = false, | |
maxDelay = 60000, | |
onRetry = null | |
} = {}) => async (...args) => { | |
let tries = 1 | |
while (true) { | |
try { | |
return await fn.apply(this, args) | |
} catch (error) { | |
if (!(error instanceof Retry) || maxTries && tries >= maxTries) { | |
throw error | |
} | |
const waitTime = expBackoff ? | |
Math.min(maxDelay, Math.pow(2, tries - 1) * dt) : | |
dt | |
if (onRetry) { onRetry({ error, tries, waitTime }) } | |
tries += 1 | |
await new Promise(resolve => setTimeout(resolve, waitTime)) | |
} | |
} | |
} | |
// --- Usage examples: --- | |
(async () => { | |
const log = msg => document.getElementById('log').innerHTML += msg + '\n' | |
const delay = (dt = 1000) => new Promise(resolve => setTimeout(resolve, dt)) | |
const onRetry = ({ tries, waitTime }) => log(`Attempt number ${tries} failed, waiting: ${waitTime}ms`) | |
let startTime | |
const sketchyFunction = async (msg) => { | |
await delay() | |
if ((Date.now() - startTime) <= 8000){ | |
throw new Error('Something went wrong') | |
} else { | |
log(msg) | |
} | |
} | |
const linearDelay = withRetry( | |
(msg) => sketchyFunction(msg).catch(e => Promise.reject(new Retry)), | |
{ onRetry } | |
) | |
const expBackoff = withRetry( | |
(msg) => sketchyFunction(msg).catch(e => Promise.reject(new Retry)), | |
{ onRetry, expBackoff: true } | |
) | |
log('Linear delay') | |
startTime = Date.now() | |
await linearDelay("hello world") | |
log('Exponential backoff') | |
startTime = Date.now() | |
await expBackoff("hello again") | |
})() |
name: Retry Utilities Example | |
description: Helpers for automatic retrying of sketchy processes | |
authors: | |
- Jasper Palfree @wellcaffeinated | |
normalize_css: no | |
wrap: b | |
panel_js: 2 |
// --- | |
// Helpers for automatic retrying of sketchy processes. | |
// Linear delay or exponential backoff | |
// Made by @wellcaffeinated | |
// No copyright | |
// --- | |
// Throw an instance of this in order to continue retrying | |
export class Retry extends Error {} | |
// Use this to wrap a function that may fail. If the function | |
// throws an instance of Retry, it will be attempted again | |
// until it resolves or throws anything else | |
export const withRetry = (fn, { | |
maxTries = false, | |
dt = 1000, | |
expBackoff = false, | |
maxDelay = 60000, | |
onRetry = null | |
} = {}) => async (...args) => { | |
let tries = 1 | |
while (true) { | |
try { | |
return await fn.apply(this, args) | |
} catch (error) { | |
if (!(error instanceof Retry) || maxTries && tries >= maxTries) { | |
throw error | |
} | |
const waitTime = expBackoff ? | |
Math.min(maxDelay, Math.pow(2, tries - 1) * dt) : | |
dt | |
if (onRetry) { onRetry({ error, tries, waitTime }) } | |
tries += 1 | |
await new Promise(resolve => setTimeout(resolve, waitTime)) | |
} | |
} | |
} |