UNPKG

1.66 kBJavaScriptView Raw
1'use strict';
2const retry = require('retry');
3
4class AbortError extends Error {
5 constructor(message) {
6 super();
7
8 if (message instanceof Error) {
9 this.originalError = message;
10 ({message} = message);
11 } else {
12 this.originalError = new Error(message);
13 this.originalError.stack = this.stack;
14 }
15
16 this.name = 'AbortError';
17 this.message = message;
18 }
19}
20
21const decorateErrorWithCounts = (error, attemptNumber, options) => {
22 // Minus 1 from attemptNumber because the first attempt does not count as a retry
23 const retriesLeft = options.retries - (attemptNumber - 1);
24
25 error.attemptNumber = attemptNumber;
26 error.retriesLeft = retriesLeft;
27 return error;
28};
29
30const pRetry = (input, options) => new Promise((resolve, reject) => {
31 options = {
32 onFailedAttempt: () => {},
33 retries: 10,
34 ...options
35 };
36
37 const operation = retry.operation(options);
38
39 operation.attempt(async attemptNumber => {
40 try {
41 resolve(await input(attemptNumber));
42 } catch (error) {
43 if (!(error instanceof Error)) {
44 reject(new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`));
45 return;
46 }
47
48 if (error instanceof AbortError) {
49 operation.stop();
50 reject(error.originalError);
51 } else if (error instanceof TypeError) {
52 operation.stop();
53 reject(error);
54 } else {
55 decorateErrorWithCounts(error, attemptNumber, options);
56 options.onFailedAttempt(error);
57
58 if (!operation.retry(error)) {
59 reject(operation.mainError());
60 }
61 }
62 }
63 });
64});
65
66module.exports = pRetry;
67// TODO: remove this in the next major version
68module.exports.default = pRetry;
69
70module.exports.AbortError = AbortError;