Skip to content

Instantly share code, notes, and snippets.

@wellcaffeinated
Last active April 16, 2022 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wellcaffeinated/df1dc4bea62688c8f372d2b76b189d32 to your computer and use it in GitHub Desktop.
Save wellcaffeinated/df1dc4bea62688c8f372d2b76b189d32 to your computer and use it in GitHub Desktop.
Helpers for automatic retrying of sketchy processes. Linear delay or exponential backoff. by @wellcaffeinated
<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))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment