Skip to content

Commit ccbc741

Browse files
committed
feat: added onRetry option for retry fn
1 parent d133b61 commit ccbc741

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

docs/async/retry.mdx

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ The `times` option defaults to `3`. The `delay` option (defaults to null) can sp
1111

1212
The `backoff` option is like delay but uses a function to sleep -- makes for easy exponential backoff.
1313

14+
The `onRetry` option is a Function that is invoked after a new retry is performed. It's passed the Error that triggered it as a parameter and the attempt number.
15+
1416
```ts
1517
import * as _ from 'radashi'
1618

@@ -20,4 +22,10 @@ await _.retry({ times: 2, delay: 1000 }, api.users.list)
2022

2123
// exponential backoff
2224
await _.retry({ backoff: i => 10 ** i }, api.users.list)
25+
26+
// onRetry usage
27+
await _.retry(
28+
{ onRetry: (err, i) => console.log(`Trying again... Attempt: ${i}`) },
29+
api.users.list,
30+
)
2331
```

src/async/retry.ts

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { sleep, tryit } from 'radashi'
33
export type RetryOptions = {
44
times?: number
55
delay?: number | null
6+
onRetry?: (err: Error, num: number) => void
67
backoff?: (count: number) => number
78
}
89

@@ -24,6 +25,7 @@ export async function retry<TResponse>(
2425
const times = options?.times ?? 3
2526
const delay = options?.delay
2627
const backoff = options?.backoff ?? null
28+
const onRetry = options?.onRetry ?? null
2729
let i = 0
2830
while (true) {
2931
const [err, result] = (await tryit(func)((err: any) => {
@@ -38,6 +40,9 @@ export async function retry<TResponse>(
3840
if (++i >= times) {
3941
throw err
4042
}
43+
if (onRetry) {
44+
onRetry(err, i)
45+
}
4146
if (delay) {
4247
await sleep(delay)
4348
}

tests/async/retry.test.ts

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// cSpell:ignore backoffs
22

3-
import * as _ from 'radashi'
43
import type { RetryOptions } from 'radashi'
4+
import * as _ from 'radashi'
55

66
const cast = <T = RetryOptions>(value: any): T => value
77

@@ -16,9 +16,11 @@ describe('retry', () => {
1616
expect(result).toBe('hello')
1717
})
1818
test('simple + quick + happy path', async () => {
19-
const result = await _.retry(cast(null), async () => {
19+
const onRetry = vi.fn()
20+
const result = await _.retry({ onRetry }, async () => {
2021
return 'hello'
2122
})
23+
expect(onRetry).not.toBeCalled()
2224
expect(result).toBe('hello')
2325
})
2426
test('retries on failure', async () => {
@@ -32,6 +34,19 @@ describe('retry', () => {
3234
})
3335
expect(result).toBe('hello')
3436
})
37+
test('call onRetry function on retries', async () => {
38+
let failedOnce = false
39+
const onRetry = vi.fn()
40+
const result = await _.retry({ onRetry }, async _bail => {
41+
if (!failedOnce) {
42+
failedOnce = true
43+
throw 'Failing for test'
44+
}
45+
return 'hello'
46+
})
47+
expect(onRetry).toBeCalledWith('Failing for test', 1)
48+
expect(result).toBe('hello')
49+
})
3550
test('quits on bail', async () => {
3651
try {
3752
await _.retry({}, async bail => {

0 commit comments

Comments
 (0)