File tree Expand file tree Collapse file tree 4 files changed +76
-1
lines changed Expand file tree Collapse file tree 4 files changed +76
-1
lines changed Original file line number Diff line number Diff line change @@ -41,6 +41,28 @@ export type Options = {
41
41
*/
42
42
readonly onFailedAttempt ?: ( error : FailedAttemptError ) => void | Promise < void > ;
43
43
44
+ /**
45
+ Decide if a retry should occur based on the error. Returning true triggers a retry, false aborts with the error.
46
+
47
+ It is not called for `TypeError` (except network errors) and `AbortError`.
48
+
49
+ @param error - The error thrown by the input function.
50
+
51
+ @example
52
+ ```
53
+ import pRetry from 'p-retry';
54
+
55
+ const run = async () => { … };
56
+
57
+ const result = await pRetry(run, {
58
+ shouldRetry: error => !(error instanceof CustomError);
59
+ });
60
+ ```
61
+
62
+ In the example above, the operation will be retried unless the error is an instance of `CustomError`.
63
+ */
64
+ readonly shouldRetry ?: ( error : FailedAttemptError ) => boolean | Promise < boolean > ;
65
+
44
66
/**
45
67
You can abort retrying using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
46
68
Original file line number Diff line number Diff line change @@ -32,6 +32,7 @@ export default async function pRetry(input, options) {
32
32
options = {
33
33
onFailedAttempt ( ) { } ,
34
34
retries : 10 ,
35
+ shouldRetry : ( ) => true ,
35
36
...options ,
36
37
} ;
37
38
@@ -70,7 +71,14 @@ export default async function pRetry(input, options) {
70
71
throw error ;
71
72
}
72
73
73
- await options . onFailedAttempt ( decorateErrorWithCounts ( error , attemptNumber , options ) ) ;
74
+ decorateErrorWithCounts ( error , attemptNumber , options ) ;
75
+
76
+ if ( ! ( await options . shouldRetry ( error ) ) ) {
77
+ operation . stop ( ) ;
78
+ reject ( error ) ;
79
+ }
80
+
81
+ await options . onFailedAttempt ( error ) ;
74
82
75
83
if ( ! operation . retry ( error ) ) {
76
84
throw operation . mainError ( ) ;
Original file line number Diff line number Diff line change @@ -99,6 +99,26 @@ const result = await pRetry(run, {
99
99
100
100
If the ` onFailedAttempt ` function throws, all retries will be aborted and the original promise will reject with the thrown error.
101
101
102
+ ##### shouldRetry(error)
103
+
104
+ Type: ` Function `
105
+
106
+ Decide if a retry should occur based on the error. Returning true triggers a retry, false aborts with the error.
107
+
108
+ It is not called for ` TypeError ` (except network errors) and ` AbortError ` .
109
+
110
+ ``` js
111
+ import pRetry from ' p-retry' ;
112
+
113
+ const run = async () => { … };
114
+
115
+ const result = await pRetry (run, {
116
+ shouldRetry : error => ! (error instanceof CustomError);
117
+ });
118
+ ```
119
+
120
+ In the example above, the operation will be retried unless the error is an instance of ` CustomError ` .
121
+
102
122
##### signal
103
123
104
124
Type: [ ` AbortSignal ` ] ( https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal )
Original file line number Diff line number Diff line change @@ -277,3 +277,28 @@ test('preserves the abort reason', async t => {
277
277
278
278
t . is ( index , 3 ) ;
279
279
} ) ;
280
+
281
+ test ( 'should retry only when shouldRetry returns true' , async t => {
282
+ t . plan ( 2 ) ;
283
+
284
+ const shouldRetryError = new Error ( 'should-retry' ) ;
285
+ const customError = new Error ( 'custom-error' ) ;
286
+
287
+ let index = 0 ;
288
+
289
+ await t . throwsAsync ( pRetry ( async ( ) => {
290
+ await delay ( 40 ) ;
291
+ index ++ ;
292
+ const error = index < 3 ? shouldRetryError : customError ;
293
+ throw error ;
294
+ } , {
295
+ async shouldRetry ( error ) {
296
+ return error . message === shouldRetryError . message ;
297
+ } ,
298
+ retries : 10 ,
299
+ } ) , {
300
+ is : customError ,
301
+ } ) ;
302
+
303
+ t . is ( index , 3 ) ;
304
+ } ) ;
You can’t perform that action at this time.
0 commit comments