@common.js/p-retry 6.2.1 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/index.d.ts +167 -34
- package/index.js +326 -127
- package/package.json +27 -11
package/README.md
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
The [p-retry](https://www.npmjs.com/package/p-retry) package exported as CommonJS modules.
|
|
4
4
|
|
|
5
|
-
Exported from [p-retry@
|
|
5
|
+
Exported from [p-retry@8.0.0](https://www.npmjs.com/package/p-retry/v/8.0.0) using https://github.com/etienne-martin/common.js.
|
package/index.d.ts
CHANGED
|
@@ -1,36 +1,78 @@
|
|
|
1
|
-
import {type OperationOptions} from 'retry';
|
|
2
|
-
|
|
3
1
|
export class AbortError extends Error {
|
|
4
2
|
readonly name: 'AbortError';
|
|
5
3
|
readonly originalError: Error;
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
|
-
Abort retrying and reject the promise.
|
|
6
|
+
Abort retrying and reject the promise. No callback functions will be called.
|
|
9
7
|
|
|
10
8
|
@param message - An error message or a custom error.
|
|
11
9
|
*/
|
|
12
10
|
constructor(message: string | Error);
|
|
13
11
|
}
|
|
14
12
|
|
|
15
|
-
export type
|
|
13
|
+
export type RetryContext = {
|
|
14
|
+
readonly error: Error;
|
|
16
15
|
readonly attemptNumber: number;
|
|
17
16
|
readonly retriesLeft: number;
|
|
18
|
-
|
|
17
|
+
readonly retriesConsumed: number;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
The delay in milliseconds before the next retry attempt.
|
|
21
|
+
|
|
22
|
+
This is calculated based on `minTimeout`, `factor`, `maxTimeout`, and `randomize` options.
|
|
23
|
+
|
|
24
|
+
Note: The actual delay may be shorter if it would exceed `maxRetryTime`.
|
|
25
|
+
This is `0` when the retry is skipped or when no retry will occur based on the checks completed before the current callback runs.
|
|
26
|
+
*/
|
|
27
|
+
readonly retryDelay: number;
|
|
28
|
+
};
|
|
19
29
|
|
|
20
30
|
export type Options = {
|
|
21
31
|
/**
|
|
22
|
-
Callback invoked on each
|
|
32
|
+
Callback invoked on each failure. Receives a context object containing the error and retry state information.
|
|
33
|
+
|
|
34
|
+
The function is called after `shouldConsumeRetry` and before `shouldRetry`, for all errors except `AbortError`.
|
|
35
|
+
|
|
36
|
+
The function is not called on `AbortError`.
|
|
37
|
+
|
|
38
|
+
@example
|
|
39
|
+
```
|
|
40
|
+
import pRetry from 'p-retry';
|
|
41
|
+
|
|
42
|
+
const run = async () => {
|
|
43
|
+
const response = await fetch('https://sindresorhus.com/unicorn');
|
|
44
|
+
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
throw new Error(response.statusText);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return response.json();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const result = await pRetry(run, {
|
|
53
|
+
onFailedAttempt: ({error, attemptNumber, retriesLeft, retriesConsumed, retryDelay}) => {
|
|
54
|
+
console.log(`Attempt ${attemptNumber} failed. Retrying in ${retryDelay}ms. ${retriesLeft} retries left.`);
|
|
55
|
+
// 1st request => Attempt 1 failed. Retrying in 1000ms. 5 retries left.
|
|
56
|
+
// 2nd request => Attempt 2 failed. Retrying in 2000ms. 4 retries left.
|
|
57
|
+
// …
|
|
58
|
+
},
|
|
59
|
+
retries: 5
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log(result);
|
|
63
|
+
```
|
|
23
64
|
|
|
24
65
|
The `onFailedAttempt` function can return a promise. For example, to add a [delay](https://github.com/sindresorhus/delay):
|
|
25
66
|
|
|
67
|
+
@example
|
|
26
68
|
```
|
|
27
69
|
import pRetry from 'p-retry';
|
|
28
70
|
import delay from 'delay';
|
|
29
71
|
|
|
30
|
-
const run = async () => {
|
|
72
|
+
const run = async () => { … };
|
|
31
73
|
|
|
32
74
|
const result = await pRetry(run, {
|
|
33
|
-
onFailedAttempt: async
|
|
75
|
+
onFailedAttempt: async () => {
|
|
34
76
|
console.log('Waiting for 1 second before retrying');
|
|
35
77
|
await delay(1000);
|
|
36
78
|
}
|
|
@@ -39,14 +81,14 @@ export type Options = {
|
|
|
39
81
|
|
|
40
82
|
If the `onFailedAttempt` function throws, all retries will be aborted and the original promise will reject with the thrown error.
|
|
41
83
|
*/
|
|
42
|
-
readonly onFailedAttempt?: (
|
|
84
|
+
readonly onFailedAttempt?: (context: RetryContext) => void | Promise<void>;
|
|
43
85
|
|
|
44
86
|
/**
|
|
45
|
-
Decide if a retry should occur based on the
|
|
87
|
+
Decide if a retry should occur based on the context. Returning true triggers a retry, false aborts with the error.
|
|
46
88
|
|
|
47
|
-
|
|
89
|
+
The function is called after `onFailedAttempt` and `shouldConsumeRetry`.
|
|
48
90
|
|
|
49
|
-
|
|
91
|
+
The function is not called on `AbortError`, `TypeError` (except network errors), or if `retries` or `maxRetryTime` are exhausted.
|
|
50
92
|
|
|
51
93
|
@example
|
|
52
94
|
```
|
|
@@ -55,13 +97,91 @@ export type Options = {
|
|
|
55
97
|
const run = async () => { … };
|
|
56
98
|
|
|
57
99
|
const result = await pRetry(run, {
|
|
58
|
-
shouldRetry: error => !(error instanceof CustomError)
|
|
100
|
+
shouldRetry: ({error, attemptNumber, retriesLeft}) => !(error instanceof CustomError)
|
|
59
101
|
});
|
|
60
102
|
```
|
|
61
103
|
|
|
62
104
|
In the example above, the operation will be retried unless the error is an instance of `CustomError`.
|
|
105
|
+
|
|
106
|
+
If the `shouldRetry` function throws, all retries will be aborted and the original promise will reject with the thrown error.
|
|
107
|
+
*/
|
|
108
|
+
readonly shouldRetry?: (context: RetryContext) => boolean | Promise<boolean>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
Decide if this failure should consume a retry from the `retries` budget.
|
|
112
|
+
|
|
113
|
+
When `false` is returned, the failure will not consume a retry or increment backoff values, but is still subject to `maxRetryTime`.
|
|
114
|
+
|
|
115
|
+
The function is called before `onFailedAttempt` and `shouldRetry`.
|
|
116
|
+
|
|
117
|
+
The function is not called on `AbortError`.
|
|
118
|
+
|
|
119
|
+
@example
|
|
120
|
+
```
|
|
121
|
+
import pRetry from 'p-retry';
|
|
122
|
+
|
|
123
|
+
const run = async () => { … };
|
|
124
|
+
|
|
125
|
+
const result = await pRetry(run, {
|
|
126
|
+
retries: 2,
|
|
127
|
+
shouldConsumeRetry: ({error, retriesLeft}) => {
|
|
128
|
+
console.log(`Retries left: ${retriesLeft}`);
|
|
129
|
+
return !(error instanceof RateLimitError);
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
In the example above, `RateLimitError`s will not decrement the available `retries`.
|
|
135
|
+
|
|
136
|
+
If the `shouldConsumeRetry` function throws, all retries will be aborted and the original promise will reject with the thrown error.
|
|
63
137
|
*/
|
|
64
|
-
readonly
|
|
138
|
+
readonly shouldConsumeRetry?: (context: RetryContext) => boolean | Promise<boolean>;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
The maximum amount of times to retry the operation.
|
|
142
|
+
|
|
143
|
+
@default 10
|
|
144
|
+
*/
|
|
145
|
+
readonly retries?: number;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
The exponential factor to use.
|
|
149
|
+
|
|
150
|
+
@default 2
|
|
151
|
+
*/
|
|
152
|
+
readonly factor?: number;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
The number of milliseconds before starting the first retry.
|
|
156
|
+
|
|
157
|
+
Set this to `0` to retry immediately with no delay.
|
|
158
|
+
|
|
159
|
+
@default 1000
|
|
160
|
+
*/
|
|
161
|
+
readonly minTimeout?: number;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
The maximum number of milliseconds between two retries.
|
|
165
|
+
|
|
166
|
+
@default Infinity
|
|
167
|
+
*/
|
|
168
|
+
readonly maxTimeout?: number;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
Randomizes the timeouts by multiplying with a factor between 1 and 2.
|
|
172
|
+
|
|
173
|
+
@default false
|
|
174
|
+
*/
|
|
175
|
+
readonly randomize?: boolean;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
The maximum time (in milliseconds) that the retried operation is allowed to run.
|
|
179
|
+
|
|
180
|
+
@default Infinity
|
|
181
|
+
|
|
182
|
+
Measured with a monotonic clock (`performance.now()`) so system clock adjustments do not affect the limit.
|
|
183
|
+
*/
|
|
184
|
+
readonly maxRetryTime?: number;
|
|
65
185
|
|
|
66
186
|
/**
|
|
67
187
|
You can abort retrying using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
|
|
@@ -84,22 +204,31 @@ export type Options = {
|
|
|
84
204
|
}
|
|
85
205
|
```
|
|
86
206
|
*/
|
|
87
|
-
readonly signal?: AbortSignal;
|
|
88
|
-
|
|
207
|
+
readonly signal?: AbortSignal | undefined;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
Prevents retry timeouts from keeping the process alive.
|
|
211
|
+
|
|
212
|
+
Only affects platforms with a `.unref()` method on timeouts, such as Node.js.
|
|
213
|
+
|
|
214
|
+
@default false
|
|
215
|
+
*/
|
|
216
|
+
readonly unref?: boolean;
|
|
217
|
+
};
|
|
89
218
|
|
|
90
219
|
/**
|
|
91
220
|
Returns a `Promise` that is fulfilled when calling `input` returns a fulfilled promise. If calling `input` returns a rejected promise, `input` is called again until the max retries are reached, it then rejects with the last rejection reason.
|
|
92
221
|
|
|
93
|
-
Does not retry on most `TypeErrors`, with the exception of network errors. This is done on a best case basis as different browsers have different [messages](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful) to indicate this.
|
|
94
|
-
|
|
222
|
+
Does not retry on most `TypeErrors`, with the exception of network errors. This is done on a best case basis as different browsers have different [messages](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful) to indicate this. See [whatwg/fetch#526 (comment)](https://github.com/whatwg/fetch/issues/526#issuecomment-554604080)
|
|
223
|
+
|
|
224
|
+
Non-network `TypeError`s always abort retries, even if `shouldConsumeRetry` or `shouldRetry` would otherwise allow another attempt.
|
|
95
225
|
|
|
96
226
|
@param input - Receives the number of attempts as the first argument and is expected to return a `Promise` or any value.
|
|
97
|
-
@param options - Options
|
|
227
|
+
@param options - Options for configuring the retry behavior.
|
|
98
228
|
|
|
99
229
|
@example
|
|
100
230
|
```
|
|
101
231
|
import pRetry, {AbortError} from 'p-retry';
|
|
102
|
-
import fetch from 'node-fetch';
|
|
103
232
|
|
|
104
233
|
const run = async () => {
|
|
105
234
|
const response = await fetch('https://sindresorhus.com/unicorn');
|
|
@@ -113,22 +242,26 @@ const run = async () => {
|
|
|
113
242
|
};
|
|
114
243
|
|
|
115
244
|
console.log(await pRetry(run, {retries: 5}));
|
|
116
|
-
|
|
117
|
-
// With the `onFailedAttempt` option:
|
|
118
|
-
const result = await pRetry(run, {
|
|
119
|
-
onFailedAttempt: error => {
|
|
120
|
-
console.log(`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.`);
|
|
121
|
-
// 1st request => Attempt 1 failed. There are 4 retries left.
|
|
122
|
-
// 2nd request => Attempt 2 failed. There are 3 retries left.
|
|
123
|
-
// …
|
|
124
|
-
},
|
|
125
|
-
retries: 5
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
console.log(result);
|
|
129
245
|
```
|
|
130
246
|
*/
|
|
131
247
|
export default function pRetry<T>(
|
|
132
|
-
input: (
|
|
248
|
+
input: (attemptNumber: number) => PromiseLike<T> | T,
|
|
133
249
|
options?: Options
|
|
134
250
|
): Promise<T>;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
Wrap a function so that each call is automatically retried on failure.
|
|
254
|
+
|
|
255
|
+
@example
|
|
256
|
+
```
|
|
257
|
+
import {makeRetriable} from 'p-retry';
|
|
258
|
+
|
|
259
|
+
const fetchWithRetry = makeRetriable(fetch, {retries: 5});
|
|
260
|
+
|
|
261
|
+
const response = await fetchWithRetry('https://sindresorhus.com/unicorn');
|
|
262
|
+
```
|
|
263
|
+
*/
|
|
264
|
+
export function makeRetriable<Arguments extends readonly unknown[], Result>(
|
|
265
|
+
function_: (...arguments_: Arguments) => PromiseLike<Result> | Result,
|
|
266
|
+
options?: Options
|
|
267
|
+
): (...arguments_: Arguments) => Promise<Result>;
|
package/index.js
CHANGED
|
@@ -14,9 +14,11 @@ _export(exports, {
|
|
|
14
14
|
},
|
|
15
15
|
default: function() {
|
|
16
16
|
return pRetry;
|
|
17
|
+
},
|
|
18
|
+
makeRetriable: function() {
|
|
19
|
+
return makeRetriable;
|
|
17
20
|
}
|
|
18
21
|
});
|
|
19
|
-
var _retry = /*#__PURE__*/ _interopRequireDefault(require("retry"));
|
|
20
22
|
var _isNetworkError = /*#__PURE__*/ _interopRequireDefault(require("is-network-error"));
|
|
21
23
|
function _assertThisInitialized(self) {
|
|
22
24
|
if (self === void 0) {
|
|
@@ -310,7 +312,42 @@ var __generator = (void 0) && (void 0).__generator || function(thisArg, body) {
|
|
|
310
312
|
};
|
|
311
313
|
}
|
|
312
314
|
};
|
|
313
|
-
var _options, _options1, _options2;
|
|
315
|
+
var _options, _options1, _options2, _options3, _options4, _options5, _options6, _options7, _options8;
|
|
316
|
+
function validateRetries(retries) {
|
|
317
|
+
if (typeof retries === "number") {
|
|
318
|
+
if (retries < 0) {
|
|
319
|
+
throw new TypeError("Expected `retries` to be a non-negative number.");
|
|
320
|
+
}
|
|
321
|
+
if (Number.isNaN(retries)) {
|
|
322
|
+
throw new TypeError("Expected `retries` to be a valid number or Infinity, got NaN.");
|
|
323
|
+
}
|
|
324
|
+
} else if (retries !== undefined) {
|
|
325
|
+
throw new TypeError("Expected `retries` to be a number or Infinity.");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function validateNumberOption(name, value) {
|
|
329
|
+
var ref = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {}, _min = ref.min, min = _min === void 0 ? 0 : _min, _allowInfinity = ref.allowInfinity, allowInfinity = _allowInfinity === void 0 ? false : _allowInfinity;
|
|
330
|
+
if (value === undefined) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
334
|
+
throw new TypeError("Expected `".concat(name, "` to be a number").concat(allowInfinity ? " or Infinity" : "", "."));
|
|
335
|
+
}
|
|
336
|
+
if (!allowInfinity && !Number.isFinite(value)) {
|
|
337
|
+
throw new TypeError("Expected `".concat(name, "` to be a finite number."));
|
|
338
|
+
}
|
|
339
|
+
if (value < min) {
|
|
340
|
+
throw new TypeError("Expected `".concat(name, "` to be ≥ ").concat(min, "."));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function validateFunctionOption(name, value) {
|
|
344
|
+
if (value === undefined) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (typeof value !== "function") {
|
|
348
|
+
throw new TypeError("Expected `".concat(name, "` to be a function."));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
314
351
|
var AbortError = /*#__PURE__*/ function(Error1) {
|
|
315
352
|
"use strict";
|
|
316
353
|
_inherits(AbortError, Error1);
|
|
@@ -332,141 +369,303 @@ var AbortError = /*#__PURE__*/ function(Error1) {
|
|
|
332
369
|
}
|
|
333
370
|
return AbortError;
|
|
334
371
|
}(_wrapNativeSuper(Error));
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
var
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
return
|
|
341
|
-
}
|
|
342
|
-
function
|
|
372
|
+
function calculateDelay(retriesConsumed, options) {
|
|
373
|
+
var attempt = Math.max(1, retriesConsumed + 1);
|
|
374
|
+
var random = options.randomize ? Math.random() + 1 : 1;
|
|
375
|
+
var timeout = Math.round(random * options.minTimeout * Math.pow(options.factor, attempt - 1));
|
|
376
|
+
timeout = Math.min(timeout, options.maxTimeout);
|
|
377
|
+
return timeout;
|
|
378
|
+
}
|
|
379
|
+
function calculateRemainingTime(start, max) {
|
|
380
|
+
if (!Number.isFinite(max)) {
|
|
381
|
+
return max;
|
|
382
|
+
}
|
|
383
|
+
return max - (performance.now() - start);
|
|
384
|
+
}
|
|
385
|
+
function delayForRetry(delay, options) {
|
|
386
|
+
return _delayForRetry.apply(this, arguments);
|
|
387
|
+
}
|
|
388
|
+
function _delayForRetry() {
|
|
389
|
+
_delayForRetry = _asyncToGenerator(function(delay, options) {
|
|
390
|
+
return __generator(this, function(_state) {
|
|
391
|
+
switch(_state.label){
|
|
392
|
+
case 0:
|
|
393
|
+
if (delay <= 0) {
|
|
394
|
+
return [
|
|
395
|
+
2
|
|
396
|
+
];
|
|
397
|
+
}
|
|
398
|
+
return [
|
|
399
|
+
4,
|
|
400
|
+
new Promise(function(resolve, reject) {
|
|
401
|
+
var ref;
|
|
402
|
+
var onAbort = function() {
|
|
403
|
+
var ref;
|
|
404
|
+
clearTimeout(timeoutToken);
|
|
405
|
+
(ref = options.signal) === null || ref === void 0 ? void 0 : ref.removeEventListener("abort", onAbort);
|
|
406
|
+
reject(options.signal.reason);
|
|
407
|
+
};
|
|
408
|
+
var timeoutToken = setTimeout(function() {
|
|
409
|
+
var ref;
|
|
410
|
+
(ref = options.signal) === null || ref === void 0 ? void 0 : ref.removeEventListener("abort", onAbort);
|
|
411
|
+
resolve();
|
|
412
|
+
}, delay);
|
|
413
|
+
if (options.unref) {
|
|
414
|
+
var ref1;
|
|
415
|
+
(ref1 = timeoutToken.unref) === null || ref1 === void 0 ? void 0 : ref1.call(timeoutToken);
|
|
416
|
+
}
|
|
417
|
+
(ref = options.signal) === null || ref === void 0 ? void 0 : ref.addEventListener("abort", onAbort, {
|
|
418
|
+
once: true
|
|
419
|
+
});
|
|
420
|
+
})
|
|
421
|
+
];
|
|
422
|
+
case 1:
|
|
423
|
+
_state.sent();
|
|
424
|
+
return [
|
|
425
|
+
2
|
|
426
|
+
];
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
return _delayForRetry.apply(this, arguments);
|
|
431
|
+
}
|
|
432
|
+
function onAttemptFailure(_) {
|
|
433
|
+
return _onAttemptFailure.apply(this, arguments);
|
|
434
|
+
}
|
|
435
|
+
function _onAttemptFailure() {
|
|
436
|
+
_onAttemptFailure = _asyncToGenerator(function(param) {
|
|
437
|
+
var error, attemptNumber, retriesConsumed, startTime, options, ref, ref1, normalizedError, retriesLeft, _maxRetryTime, maxRetryTime, delayTime, remainingTimeBeforeCallbacks, context, consumeRetryContext, consumeRetry, effectiveDelay, context1, remainingTime, remainingTimeAfterShouldRetry, ref2, finalDelay;
|
|
438
|
+
return __generator(this, function(_state) {
|
|
439
|
+
switch(_state.label){
|
|
440
|
+
case 0:
|
|
441
|
+
error = param.error, attemptNumber = param.attemptNumber, retriesConsumed = param.retriesConsumed, startTime = param.startTime, options = param.options;
|
|
442
|
+
normalizedError = _instanceof(error, Error) ? error : new TypeError('Non-error was thrown: "'.concat(error, '". You should only throw errors.'));
|
|
443
|
+
if (_instanceof(normalizedError, AbortError)) {
|
|
444
|
+
throw normalizedError.originalError;
|
|
445
|
+
}
|
|
446
|
+
retriesLeft = Number.isFinite(options.retries) ? Math.max(0, options.retries - retriesConsumed) : options.retries;
|
|
447
|
+
maxRetryTime = (_maxRetryTime = options.maxRetryTime) !== null && _maxRetryTime !== void 0 ? _maxRetryTime : Number.POSITIVE_INFINITY;
|
|
448
|
+
delayTime = calculateDelay(retriesConsumed, options);
|
|
449
|
+
remainingTimeBeforeCallbacks = calculateRemainingTime(startTime, maxRetryTime);
|
|
450
|
+
if (!(remainingTimeBeforeCallbacks <= 0)) return [
|
|
451
|
+
3,
|
|
452
|
+
2
|
|
453
|
+
];
|
|
454
|
+
context = Object.freeze({
|
|
455
|
+
error: normalizedError,
|
|
456
|
+
attemptNumber: attemptNumber,
|
|
457
|
+
retriesLeft: retriesLeft,
|
|
458
|
+
retriesConsumed: retriesConsumed,
|
|
459
|
+
retryDelay: 0
|
|
460
|
+
});
|
|
461
|
+
return [
|
|
462
|
+
4,
|
|
463
|
+
options.onFailedAttempt(context)
|
|
464
|
+
];
|
|
465
|
+
case 1:
|
|
466
|
+
_state.sent();
|
|
467
|
+
throw normalizedError;
|
|
468
|
+
case 2:
|
|
469
|
+
consumeRetryContext = Object.freeze({
|
|
470
|
+
error: normalizedError,
|
|
471
|
+
attemptNumber: attemptNumber,
|
|
472
|
+
retriesLeft: retriesLeft,
|
|
473
|
+
retriesConsumed: retriesConsumed,
|
|
474
|
+
retryDelay: retriesLeft > 0 ? delayTime : 0
|
|
475
|
+
});
|
|
476
|
+
return [
|
|
477
|
+
4,
|
|
478
|
+
options.shouldConsumeRetry(consumeRetryContext)
|
|
479
|
+
];
|
|
480
|
+
case 3:
|
|
481
|
+
consumeRetry = _state.sent();
|
|
482
|
+
effectiveDelay = consumeRetry && retriesLeft > 0 ? delayTime : 0;
|
|
483
|
+
context1 = Object.freeze({
|
|
484
|
+
error: normalizedError,
|
|
485
|
+
attemptNumber: attemptNumber,
|
|
486
|
+
retriesLeft: retriesLeft,
|
|
487
|
+
retriesConsumed: retriesConsumed,
|
|
488
|
+
retryDelay: effectiveDelay
|
|
489
|
+
});
|
|
490
|
+
return [
|
|
491
|
+
4,
|
|
492
|
+
options.onFailedAttempt(context1)
|
|
493
|
+
];
|
|
494
|
+
case 4:
|
|
495
|
+
_state.sent();
|
|
496
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) {
|
|
497
|
+
throw normalizedError;
|
|
498
|
+
}
|
|
499
|
+
remainingTime = calculateRemainingTime(startTime, maxRetryTime);
|
|
500
|
+
if (remainingTime <= 0 || retriesLeft <= 0) {
|
|
501
|
+
throw normalizedError;
|
|
502
|
+
}
|
|
503
|
+
if (_instanceof(normalizedError, TypeError) && !(0, _isNetworkError.default)(normalizedError)) {
|
|
504
|
+
throw normalizedError;
|
|
505
|
+
}
|
|
506
|
+
return [
|
|
507
|
+
4,
|
|
508
|
+
options.shouldRetry(context1)
|
|
509
|
+
];
|
|
510
|
+
case 5:
|
|
511
|
+
if (!_state.sent()) {
|
|
512
|
+
throw normalizedError;
|
|
513
|
+
}
|
|
514
|
+
remainingTimeAfterShouldRetry = calculateRemainingTime(startTime, maxRetryTime);
|
|
515
|
+
if (remainingTimeAfterShouldRetry <= 0) {
|
|
516
|
+
throw normalizedError;
|
|
517
|
+
}
|
|
518
|
+
if (!consumeRetry) {
|
|
519
|
+
;
|
|
520
|
+
(ref2 = options.signal) === null || ref2 === void 0 ? void 0 : ref2.throwIfAborted();
|
|
521
|
+
return [
|
|
522
|
+
2,
|
|
523
|
+
false
|
|
524
|
+
];
|
|
525
|
+
}
|
|
526
|
+
finalDelay = Math.min(effectiveDelay, remainingTimeAfterShouldRetry);
|
|
527
|
+
(ref = options.signal) === null || ref === void 0 ? void 0 : ref.throwIfAborted();
|
|
528
|
+
return [
|
|
529
|
+
4,
|
|
530
|
+
delayForRetry(finalDelay, options)
|
|
531
|
+
];
|
|
532
|
+
case 6:
|
|
533
|
+
_state.sent();
|
|
534
|
+
(ref1 = options.signal) === null || ref1 === void 0 ? void 0 : ref1.throwIfAborted();
|
|
535
|
+
return [
|
|
536
|
+
2,
|
|
537
|
+
true
|
|
538
|
+
];
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
return _onAttemptFailure.apply(this, arguments);
|
|
543
|
+
}
|
|
544
|
+
function pRetry(input) {
|
|
343
545
|
return _pRetry.apply(this, arguments);
|
|
344
546
|
}
|
|
345
547
|
function _pRetry() {
|
|
346
|
-
_pRetry = _asyncToGenerator(function(input
|
|
548
|
+
_pRetry = _asyncToGenerator(function(input) {
|
|
549
|
+
var options, ref, _retries, _factor, _minTimeout, _maxTimeout, _maxRetryTime, _randomize, _onFailedAttempt, _shouldRetry, _shouldConsumeRetry, attemptNumber, retriesConsumed, startTime, ref1, ref2, result, error;
|
|
550
|
+
var _arguments = arguments;
|
|
347
551
|
return __generator(this, function(_state) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
552
|
+
switch(_state.label){
|
|
553
|
+
case 0:
|
|
554
|
+
options = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
|
|
351
555
|
options = _objectSpread({}, options);
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
556
|
+
validateRetries(options.retries);
|
|
557
|
+
if (Object.hasOwn(options, "forever")) {
|
|
558
|
+
throw new Error("The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead.");
|
|
559
|
+
}
|
|
560
|
+
(_retries = (_options = options).retries) !== null && _retries !== void 0 ? _retries : _options.retries = 10;
|
|
561
|
+
(_factor = (_options1 = options).factor) !== null && _factor !== void 0 ? _factor : _options1.factor = 2;
|
|
562
|
+
(_minTimeout = (_options2 = options).minTimeout) !== null && _minTimeout !== void 0 ? _minTimeout : _options2.minTimeout = 1000;
|
|
563
|
+
(_maxTimeout = (_options3 = options).maxTimeout) !== null && _maxTimeout !== void 0 ? _maxTimeout : _options3.maxTimeout = Number.POSITIVE_INFINITY;
|
|
564
|
+
(_maxRetryTime = (_options4 = options).maxRetryTime) !== null && _maxRetryTime !== void 0 ? _maxRetryTime : _options4.maxRetryTime = Number.POSITIVE_INFINITY;
|
|
565
|
+
(_randomize = (_options5 = options).randomize) !== null && _randomize !== void 0 ? _randomize : _options5.randomize = false;
|
|
566
|
+
(_onFailedAttempt = (_options6 = options).onFailedAttempt) !== null && _onFailedAttempt !== void 0 ? _onFailedAttempt : _options6.onFailedAttempt = function() {};
|
|
567
|
+
(_shouldRetry = (_options7 = options).shouldRetry) !== null && _shouldRetry !== void 0 ? _shouldRetry : _options7.shouldRetry = function() {
|
|
356
568
|
return true;
|
|
357
569
|
};
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
var operation = _retry.default.operation(options);
|
|
361
|
-
var abortHandler = function() {
|
|
362
|
-
var ref;
|
|
363
|
-
operation.stop();
|
|
364
|
-
reject((ref = options.signal) === null || ref === void 0 ? void 0 : ref.reason);
|
|
570
|
+
(_shouldConsumeRetry = (_options8 = options).shouldConsumeRetry) !== null && _shouldConsumeRetry !== void 0 ? _shouldConsumeRetry : _options8.shouldConsumeRetry = function() {
|
|
571
|
+
return true;
|
|
365
572
|
};
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
573
|
+
// Validate numeric options and normalize edge cases
|
|
574
|
+
validateFunctionOption("onFailedAttempt", options.onFailedAttempt);
|
|
575
|
+
validateFunctionOption("shouldRetry", options.shouldRetry);
|
|
576
|
+
validateFunctionOption("shouldConsumeRetry", options.shouldConsumeRetry);
|
|
577
|
+
validateNumberOption("factor", options.factor, {
|
|
578
|
+
min: 0,
|
|
579
|
+
allowInfinity: false
|
|
580
|
+
});
|
|
581
|
+
validateNumberOption("minTimeout", options.minTimeout, {
|
|
582
|
+
min: 0,
|
|
583
|
+
allowInfinity: false
|
|
584
|
+
});
|
|
585
|
+
validateNumberOption("maxTimeout", options.maxTimeout, {
|
|
586
|
+
min: 0,
|
|
587
|
+
allowInfinity: true
|
|
588
|
+
});
|
|
589
|
+
validateNumberOption("maxRetryTime", options.maxRetryTime, {
|
|
590
|
+
min: 0,
|
|
591
|
+
allowInfinity: true
|
|
592
|
+
});
|
|
593
|
+
// Treat non-positive factor as 1 to avoid zero backoff or negative behavior
|
|
594
|
+
if (!(options.factor > 0)) {
|
|
595
|
+
options.factor = 1;
|
|
370
596
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
options.onFailedAttempt(error)
|
|
432
|
-
];
|
|
433
|
-
case 5:
|
|
434
|
-
_state.sent();
|
|
435
|
-
if (!operation.retry(error)) {
|
|
436
|
-
throw operation.mainError();
|
|
437
|
-
}
|
|
438
|
-
return [
|
|
439
|
-
3,
|
|
440
|
-
7
|
|
441
|
-
];
|
|
442
|
-
case 6:
|
|
443
|
-
finalError = _state.sent();
|
|
444
|
-
decorateErrorWithCounts(finalError, attemptNumber, options);
|
|
445
|
-
cleanUp();
|
|
446
|
-
reject(finalError);
|
|
447
|
-
return [
|
|
448
|
-
3,
|
|
449
|
-
7
|
|
450
|
-
];
|
|
451
|
-
case 7:
|
|
452
|
-
return [
|
|
453
|
-
3,
|
|
454
|
-
8
|
|
455
|
-
];
|
|
456
|
-
case 8:
|
|
457
|
-
return [
|
|
458
|
-
2
|
|
459
|
-
];
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
});
|
|
463
|
-
return function(attemptNumber) {
|
|
464
|
-
return _ref.apply(this, arguments);
|
|
465
|
-
};
|
|
466
|
-
}());
|
|
467
|
-
})
|
|
468
|
-
];
|
|
597
|
+
(ref = options.signal) === null || ref === void 0 ? void 0 : ref.throwIfAborted();
|
|
598
|
+
attemptNumber = 0;
|
|
599
|
+
retriesConsumed = 0;
|
|
600
|
+
startTime = performance.now();
|
|
601
|
+
_state.label = 1;
|
|
602
|
+
case 1:
|
|
603
|
+
if (!(Number.isFinite(options.retries) ? retriesConsumed <= options.retries : true)) return [
|
|
604
|
+
3,
|
|
605
|
+
7
|
|
606
|
+
];
|
|
607
|
+
attemptNumber++;
|
|
608
|
+
_state.label = 2;
|
|
609
|
+
case 2:
|
|
610
|
+
_state.trys.push([
|
|
611
|
+
2,
|
|
612
|
+
4,
|
|
613
|
+
,
|
|
614
|
+
6
|
|
615
|
+
]);
|
|
616
|
+
(ref1 = options.signal) === null || ref1 === void 0 ? void 0 : ref1.throwIfAborted();
|
|
617
|
+
return [
|
|
618
|
+
4,
|
|
619
|
+
input(attemptNumber)
|
|
620
|
+
];
|
|
621
|
+
case 3:
|
|
622
|
+
result = _state.sent();
|
|
623
|
+
(ref2 = options.signal) === null || ref2 === void 0 ? void 0 : ref2.throwIfAborted();
|
|
624
|
+
return [
|
|
625
|
+
2,
|
|
626
|
+
result
|
|
627
|
+
];
|
|
628
|
+
case 4:
|
|
629
|
+
error = _state.sent();
|
|
630
|
+
return [
|
|
631
|
+
4,
|
|
632
|
+
onAttemptFailure({
|
|
633
|
+
error: error,
|
|
634
|
+
attemptNumber: attemptNumber,
|
|
635
|
+
retriesConsumed: retriesConsumed,
|
|
636
|
+
startTime: startTime,
|
|
637
|
+
options: options
|
|
638
|
+
})
|
|
639
|
+
];
|
|
640
|
+
case 5:
|
|
641
|
+
if (_state.sent()) {
|
|
642
|
+
retriesConsumed++;
|
|
643
|
+
}
|
|
644
|
+
return [
|
|
645
|
+
3,
|
|
646
|
+
6
|
|
647
|
+
];
|
|
648
|
+
case 6:
|
|
649
|
+
return [
|
|
650
|
+
3,
|
|
651
|
+
1
|
|
652
|
+
];
|
|
653
|
+
case 7:
|
|
654
|
+
// Should not reach here, but in case it does, throw an error
|
|
655
|
+
throw new Error("Retry attempts exhausted without throwing an error.");
|
|
656
|
+
}
|
|
469
657
|
});
|
|
470
658
|
});
|
|
471
659
|
return _pRetry.apply(this, arguments);
|
|
472
660
|
}
|
|
661
|
+
function makeRetriable(function_, options) {
|
|
662
|
+
return function() {
|
|
663
|
+
for(var _len = arguments.length, arguments_ = new Array(_len), _key = 0; _key < _len; _key++){
|
|
664
|
+
arguments_[_key] = arguments[_key];
|
|
665
|
+
}
|
|
666
|
+
var _this = this;
|
|
667
|
+
return pRetry(function() {
|
|
668
|
+
return function_.apply(_this, arguments_);
|
|
669
|
+
}, options);
|
|
670
|
+
};
|
|
671
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@common.js/p-retry",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"description": "p-retry package exported as CommonJS modules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "etienne-martin/common.js",
|
|
7
7
|
"funding": "https://github.com/sponsors/sindresorhus",
|
|
8
8
|
"type": "commonjs",
|
|
9
|
-
"
|
|
9
|
+
"exports": {
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"default": "./index.js"
|
|
12
|
+
},
|
|
10
13
|
"sideEffects": false,
|
|
11
14
|
"engines": {
|
|
12
|
-
"node": ">=
|
|
15
|
+
"node": ">=22"
|
|
13
16
|
},
|
|
14
17
|
"scripts": {
|
|
15
18
|
"test": "xo && ava && tsd"
|
|
@@ -19,16 +22,29 @@
|
|
|
19
22
|
"index.d.ts"
|
|
20
23
|
],
|
|
21
24
|
"dependencies": {
|
|
22
|
-
"
|
|
23
|
-
"@common.js/is-network-error": "^1.0.0",
|
|
24
|
-
"retry": "^0.13.1"
|
|
25
|
+
"is-network-error": "npm:@common.js/is-network-error@1.3.3"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
|
-
"ava": "^
|
|
28
|
-
"delay": "^
|
|
29
|
-
"
|
|
30
|
-
"
|
|
28
|
+
"ava": "^6.4.1",
|
|
29
|
+
"delay": "^7.0.0",
|
|
30
|
+
"execa": "^9.6.1",
|
|
31
|
+
"tsd": "^0.33.0",
|
|
32
|
+
"xo": "^1.2.3"
|
|
33
|
+
},
|
|
34
|
+
"xo": {
|
|
35
|
+
"rules": {
|
|
36
|
+
"no-await-in-loop": "off"
|
|
37
|
+
}
|
|
31
38
|
},
|
|
32
39
|
"homepage": "https://github.com/etienne-martin/common.js#readme",
|
|
33
|
-
"
|
|
40
|
+
"commonjs": {
|
|
41
|
+
"source": {
|
|
42
|
+
"name": "p-retry",
|
|
43
|
+
"version": "8.0.0"
|
|
44
|
+
},
|
|
45
|
+
"transformRevision": 1,
|
|
46
|
+
"buildKey": "55b606486907007f9a9d30fe3a13db13a497a4d1f4947523f6ba48fb3e8335f1"
|
|
47
|
+
},
|
|
48
|
+
"main": "./index.js",
|
|
49
|
+
"types": "./index.d.ts"
|
|
34
50
|
}
|