Skip to content

Commit 30c50ef

Browse files
authored
Merge pull request #273 from DoubleData/feature/respect-abort-signal
Feature/respect abort signal
2 parents 703df66 + ad9bffb commit 30c50ef

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

spec/index.spec.ts

+58-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import http from 'http';
22
import nock from 'nock';
3-
import axios, { AxiosError, isAxiosError } from 'axios';
3+
import axios, { AxiosError, CanceledError, isAxiosError } from 'axios';
44
import axiosRetry, {
55
isNetworkError,
66
isSafeRequestError,
@@ -326,6 +326,63 @@ describe('axiosRetry(axios, { retries, retryCondition })', () => {
326326
.catch(done.fail);
327327
});
328328
});
329+
330+
describe('when request is aborted', () => {
331+
it('should clear timeout if started', (done) => {
332+
const client = axios.create();
333+
setupResponses(client, [
334+
() => nock('http://example.com').get('/test').reply(429),
335+
() => nock('http://example.com').get('/test').reply(429)
336+
]);
337+
axiosRetry(client, {
338+
retries: 1,
339+
retryCondition: () => true,
340+
retryDelay: () => 10000
341+
});
342+
const abortController = new AbortController();
343+
client
344+
.get('http://example.com/test', { signal: abortController.signal })
345+
.then(
346+
() => done.fail(),
347+
(error) => {
348+
expect(error).toBeInstanceOf(CanceledError);
349+
expect(new Date().getTime() - timeStart).toBeLessThan(300);
350+
done();
351+
}
352+
)
353+
.catch(done.fail);
354+
setTimeout(() => abortController.abort(), 200);
355+
const timeStart = new Date().getTime();
356+
});
357+
358+
it('should not start a timeout if not started yet', (done) => {
359+
const client = axios.create();
360+
setupResponses(client, [
361+
() => nock('http://example.com').get('/test').reply(429),
362+
() => nock('http://example.com').get('/test').reply(429)
363+
]);
364+
axiosRetry(client, {
365+
retries: 1,
366+
retryCondition: () => true,
367+
retryDelay: () => 10000,
368+
onRetry: async () => new Promise((resolve) => setTimeout(resolve, 100))
369+
});
370+
const abortController = new AbortController();
371+
client
372+
.get('http://example.com/test', { signal: abortController.signal })
373+
.then(
374+
() => done.fail(),
375+
(error) => {
376+
expect(error).toBeInstanceOf(CanceledError);
377+
expect(new Date().getTime() - timeStart).toBeLessThan(300);
378+
done();
379+
}
380+
)
381+
.catch(done.fail);
382+
setTimeout(() => abortController.abort(), 50);
383+
const timeStart = new Date().getTime();
384+
});
385+
});
329386
});
330387

331388
describe('when it does NOT satisfy the retry condition', () => {

src/index.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,21 @@ async function handleRetry(
252252
}
253253
config.transformRequest = [(data) => data];
254254
await onRetry(currentState.retryCount, error, config);
255-
return new Promise((resolve) => {
256-
setTimeout(() => resolve(axiosInstance(config)), delay);
255+
if (config.signal?.aborted) {
256+
return Promise.resolve(axiosInstance(config));
257+
}
258+
return new Promise((resolve, reject) => {
259+
const timeout = setTimeout(() => resolve(axiosInstance(config)), delay);
260+
if (config.signal?.addEventListener) {
261+
config.signal.addEventListener(
262+
'abort',
263+
() => {
264+
clearTimeout(timeout);
265+
resolve(axiosInstance(config));
266+
},
267+
{ once: true }
268+
);
269+
}
257270
});
258271
}
259272

0 commit comments

Comments
 (0)