UNPKG

1.32 kBJavaScriptView Raw
1// @flow
2
3type AsyncRetryOptions = {
4 maxRetries?: ?number,
5 expoBackoffMs?: ?number,
6 asyncErrorHandler?: ?(err: Error, triesExecuted: number) => Promise<void>
7}
8
9export async function sleep(periodMs: number = 0) {
10 return await new Promise(r => setTimeout(r, periodMs))
11}
12
13/**
14 * Retries the execution of an async function
15 */
16// $FlowIgnore
17export async function asyncRetry<T>(asyncFunc: (triesExecuted?: ?number) => Promise<T>, options: AsyncRetryOptions = {}): Promise<T> {
18
19 // set defaults
20 options.maxRetries = (typeof options.maxRetries === 'undefined') ? 2 : options.maxRetries
21
22 if (typeof options.maxRetries !== 'number')
23 throw new Error(`options.maxRetries is of an invalid type`)
24
25 let triesExecuted = 0
26 let nextBackoffMs = options.expoBackoffMs
27 /* eslint-disable no-constant-condition */
28 while (true) {
29 try {
30 triesExecuted++
31 return await asyncFunc(triesExecuted)
32 } catch (err) {
33 if (options.asyncErrorHandler) {
34 await options.asyncErrorHandler(err, triesExecuted)
35 }
36 if (triesExecuted > options.maxRetries) {
37 if (typeof err === 'object') {
38 err._triesExecuted = triesExecuted
39 }
40 throw err
41 }
42 if (nextBackoffMs) {
43 await sleep(nextBackoffMs)
44 nextBackoffMs *= 1.5
45 }
46 }
47 }
48}
\No newline at end of file