From 55cfa9d88820f3970b9a08682ae9778ef3d5ff7b Mon Sep 17 00:00:00 2001 From: dkwon17 Date: Tue, 7 Nov 2023 18:27:35 +0000 Subject: [PATCH] feat: exponential retries for axiosWrapper Signed-off-by: dkwon17 --- .../__tests__/axiosWrapper.spec.ts | 23 +++++++++++++++++++ .../services/axios-wrapper/axiosWrapper.ts | 11 +++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/packages/dashboard-frontend/src/services/axios-wrapper/__tests__/axiosWrapper.spec.ts b/packages/dashboard-frontend/src/services/axios-wrapper/__tests__/axiosWrapper.spec.ts index d9a141863..28cfce76f 100644 --- a/packages/dashboard-frontend/src/services/axios-wrapper/__tests__/axiosWrapper.spec.ts +++ b/packages/dashboard-frontend/src/services/axios-wrapper/__tests__/axiosWrapper.spec.ts @@ -17,6 +17,7 @@ import { AxiosWrapper, bearerTokenAuthorizationIsRequiredErrorMsg, } from '@/services/axios-wrapper/axiosWrapper'; +import * as helpers from '@/services/helpers/delay'; // mute console logs console.log = jest.fn(); @@ -26,12 +27,18 @@ describe('axiosWrapper', () => { let axiosInstance: AxiosInstance; let axiosGetMock: jest.Mock; let axiosGetSpy: jest.SpyInstance; + let delaySpy: jest.SpyInstance; beforeEach(() => { axiosInstance = mockAxios; axiosGetMock = jest.fn(); axiosInstance.get = axiosGetMock; axiosGetSpy = jest.spyOn(axiosInstance, 'get'); + delaySpy = jest.spyOn(helpers, 'delay').mockResolvedValue(); + }); + + afterEach(() => { + jest.clearAllMocks(); }); it('should retry 0 time with Bearer Token Authorization is required error message', async () => { @@ -196,6 +203,22 @@ describe('axiosWrapper', () => { expect(axiosGetSpy).toBeCalledTimes(4); } }); + + it('should have retry delay increase exponentially', async () => { + axiosGetMock + .mockRejectedValueOnce(new Error('error 1')) + .mockRejectedValueOnce(new Error('error 2')) + .mockRejectedValueOnce(new Error('error 3')) + .mockRejectedValue(new Error('error 4')); + + try { + await new AxiosWrapper(axiosInstance).get('some-url'); + fail('should fail'); + } catch (e: any) { + expect(delaySpy).toBeCalledTimes(3); + expect(delaySpy.mock.calls).toEqual([[500], [1000], [2000]]); + } + }); }); function createAxiosResponseError(message: string): { response: AxiosResponse } { diff --git a/packages/dashboard-frontend/src/services/axios-wrapper/axiosWrapper.ts b/packages/dashboard-frontend/src/services/axios-wrapper/axiosWrapper.ts index bbde721f5..8f1aaee2d 100644 --- a/packages/dashboard-frontend/src/services/axios-wrapper/axiosWrapper.ts +++ b/packages/dashboard-frontend/src/services/axios-wrapper/axiosWrapper.ts @@ -23,7 +23,8 @@ export const bearerTokenAuthorizationIsRequiredErrorMsg = 'Bearer Token Authoriz export class AxiosWrapper { protected readonly retryCount = 3; - protected readonly retryDelay = 500; + protected readonly base = 2; + protected readonly initialDelay = 500; protected readonly axiosInstance: AxiosInstance; protected readonly errorMessagesToRetry?: string; @@ -105,9 +106,11 @@ export class AxiosWrapper { throw err; } - // Retry the request after a delay. - console.warn(`Retrying request to ${url} in ${this.retryDelay} ms, ${retry} left`); - await delay(this.retryDelay); + // Retry the request after an exponential delay. + const exp = this.retryCount - retry; + const expDelay = this.initialDelay * this.base ** exp; + console.warn(`Retrying request to ${url} in ${expDelay} ms, ${retry} left`); + await delay(expDelay); return await this.doRetryFunc(fun, url, --retry); }