diff --git a/packages/rest/src/Requester.ts b/packages/rest/src/Requester.ts index 7a1f74a09..ff97ac9f8 100644 --- a/packages/rest/src/Requester.ts +++ b/packages/rest/src/Requester.ts @@ -115,9 +115,9 @@ export async function defaultRequestHandler(endpoint: string, options?: RequestO if (response.ok) return parseResponse(response, asStream); if (!retryCodes.includes(response.status)) await throwFailedRequestError(request, response); - // Retry + // Retry with exponential backoff (in milliseconds) lastStatus = response.status; - await delay(2 ** i * 0.25); + await delay(2 ** i * 250); continue; } diff --git a/packages/rest/test/unit/Requester.ts b/packages/rest/test/unit/Requester.ts index d5c6d96d4..c725a42cb 100644 --- a/packages/rest/test/unit/Requester.ts +++ b/packages/rest/test/unit/Requester.ts @@ -377,6 +377,8 @@ describe('defaultRequestHandler', () => { }); it('should return a default error if retries are unsuccessful', async () => { + jest.useFakeTimers(); + const responseContent = { error: 'msg' }; const fakeReturnValue = Promise.resolve( Promise.resolve( @@ -392,14 +394,21 @@ describe('defaultRequestHandler', () => { mockFetch.mockReturnValue(fakeReturnValue); - const error = await getError(() => + const errorPromise = getError(() => defaultRequestHandler('http://test.com', {} as RequestOptions), ); + // Fast-forward through all retry delays + await jest.runAllTimersAsync(); + + const error = await errorPromise; + expect(error.message).toBe( 'Could not successfully complete this request after 10 retries, last status code: 429. Check the applicable rate limits for this endpoint.', ); expect(error).toBeInstanceOf(GitbeakerRetryError); + + jest.useRealTimers(); }); it('should return correct properties if request is valid', async () => {