From ccbc741588c0c43775fd885118805e5b19f49a88 Mon Sep 17 00:00:00 2001 From: Gustavo Perdomo Date: Thu, 29 Aug 2024 20:55:23 -0400 Subject: [PATCH] feat: added onRetry option for retry fn --- docs/async/retry.mdx | 8 ++++++++ src/async/retry.ts | 5 +++++ tests/async/retry.test.ts | 19 +++++++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/async/retry.mdx b/docs/async/retry.mdx index c0ca01880..ce41836b2 100644 --- a/docs/async/retry.mdx +++ b/docs/async/retry.mdx @@ -11,6 +11,8 @@ The `times` option defaults to `3`. The `delay` option (defaults to null) can sp The `backoff` option is like delay but uses a function to sleep -- makes for easy exponential backoff. +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. + ```ts import * as _ from 'radashi' @@ -20,4 +22,10 @@ await _.retry({ times: 2, delay: 1000 }, api.users.list) // exponential backoff await _.retry({ backoff: i => 10 ** i }, api.users.list) + +// onRetry usage +await _.retry( + { onRetry: (err, i) => console.log(`Trying again... Attempt: ${i}`) }, + api.users.list, +) ``` diff --git a/src/async/retry.ts b/src/async/retry.ts index cde7d1dd6..d4330254f 100644 --- a/src/async/retry.ts +++ b/src/async/retry.ts @@ -3,6 +3,7 @@ import { sleep, tryit } from 'radashi' export type RetryOptions = { times?: number delay?: number | null + onRetry?: (err: Error, num: number) => void backoff?: (count: number) => number } @@ -24,6 +25,7 @@ export async function retry( const times = options?.times ?? 3 const delay = options?.delay const backoff = options?.backoff ?? null + const onRetry = options?.onRetry ?? null let i = 0 while (true) { const [err, result] = (await tryit(func)((err: any) => { @@ -38,6 +40,9 @@ export async function retry( if (++i >= times) { throw err } + if (onRetry) { + onRetry(err, i) + } if (delay) { await sleep(delay) } diff --git a/tests/async/retry.test.ts b/tests/async/retry.test.ts index 553023d14..ab6dfc828 100644 --- a/tests/async/retry.test.ts +++ b/tests/async/retry.test.ts @@ -1,7 +1,7 @@ // cSpell:ignore backoffs -import * as _ from 'radashi' import type { RetryOptions } from 'radashi' +import * as _ from 'radashi' const cast = (value: any): T => value @@ -16,9 +16,11 @@ describe('retry', () => { expect(result).toBe('hello') }) test('simple + quick + happy path', async () => { - const result = await _.retry(cast(null), async () => { + const onRetry = vi.fn() + const result = await _.retry({ onRetry }, async () => { return 'hello' }) + expect(onRetry).not.toBeCalled() expect(result).toBe('hello') }) test('retries on failure', async () => { @@ -32,6 +34,19 @@ describe('retry', () => { }) expect(result).toBe('hello') }) + test('call onRetry function on retries', async () => { + let failedOnce = false + const onRetry = vi.fn() + const result = await _.retry({ onRetry }, async _bail => { + if (!failedOnce) { + failedOnce = true + throw 'Failing for test' + } + return 'hello' + }) + expect(onRetry).toBeCalledWith('Failing for test', 1) + expect(result).toBe('hello') + }) test('quits on bail', async () => { try { await _.retry({}, async bail => {