@@ -37,10 +37,14 @@ export type RetryOptions = {
37
37
38
38
/**
39
39
* Retry function with exponential backoff.
40
+ *
41
+ * The function receives AbortSignal, attempt number starting with 0, and reset
42
+ * function that sets attempt number to -1 so that the next attempt will be
43
+ * made without delay.
40
44
*/
41
45
export async function retry < T > (
42
46
signal : AbortSignal ,
43
- fn : ( signal : AbortSignal , attempt : number ) => Promise < T > ,
47
+ fn : ( signal : AbortSignal , attempt : number , reset : ( ) => void ) => Promise < T > ,
44
48
options : RetryOptions = { } ,
45
49
) : Promise < T > {
46
50
const {
@@ -50,25 +54,41 @@ export async function retry<T>(
50
54
maxAttempts = Infinity ,
51
55
} = options ;
52
56
53
- for ( let attempt = 0 ; ; attempt ++ ) {
57
+ let attempt = 0 ;
58
+
59
+ const reset = ( ) => {
60
+ attempt = - 1 ;
61
+ } ;
62
+
63
+ while ( true ) {
54
64
try {
55
- return await fn ( signal , attempt ) ;
65
+ return await fn ( signal , attempt , reset ) ;
56
66
} catch ( error ) {
57
67
rethrowAbortError ( error ) ;
58
68
59
69
if ( attempt >= maxAttempts ) {
60
70
throw error ;
61
71
}
62
72
63
- // https://aws.amazon.com/ru/blogs/architecture/exponential-backoff-and-jitter/
64
- const backoff = Math . min ( maxDelayMs , Math . pow ( 2 , attempt ) * baseMs ) ;
65
- const delayMs = Math . round ( ( backoff * ( 1 + Math . random ( ) ) ) / 2 ) ;
73
+ let delayMs : number ;
74
+
75
+ if ( attempt === - 1 ) {
76
+ delayMs = 0 ;
77
+ } else {
78
+ // https://aws.amazon.com/ru/blogs/architecture/exponential-backoff-and-jitter/
79
+ const backoff = Math . min ( maxDelayMs , Math . pow ( 2 , attempt ) * baseMs ) ;
80
+ delayMs = Math . round ( ( backoff * ( 1 + Math . random ( ) ) ) / 2 ) ;
81
+ }
66
82
67
83
if ( onError ) {
68
84
onError ( error , attempt , delayMs ) ;
69
85
}
70
86
71
- await delay ( signal , delayMs ) ;
87
+ if ( delayMs !== 0 ) {
88
+ await delay ( signal , delayMs ) ;
89
+ }
90
+
91
+ attempt += 1 ;
72
92
}
73
93
}
74
94
}
0 commit comments