-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support retry-after header #142
Changes from all commits
1efbe6f
5c219b8
f6f6c8d
d20334d
1ec4171
8e1d2ae
27290eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import * as assert from 'assert'; | ||
import axios, {AxiosRequestConfig} from 'axios'; | ||
import * as nock from 'nock'; | ||
import * as sinon from 'sinon'; | ||
import {describe, it, afterEach} from 'mocha'; | ||
import * as rax from '../src'; | ||
import {RaxConfig} from '../src'; | ||
|
@@ -12,6 +13,7 @@ nock.disableNetConnect(); | |
describe('retry-axios', () => { | ||
let interceptorId: number | undefined; | ||
afterEach(() => { | ||
sinon.restore(); | ||
nock.cleanAll(); | ||
if (interceptorId !== undefined) { | ||
rax.detach(interceptorId); | ||
|
@@ -32,6 +34,8 @@ describe('retry-axios', () => { | |
assert.strictEqual(config!.retryDelay, 100, 'retryDelay'); | ||
assert.strictEqual(config!.instance, axios, 'axios'); | ||
assert.strictEqual(config!.backoffType, 'exponential', 'backoffType'); | ||
assert.strictEqual(config!.checkRetryAfter, true); | ||
assert.strictEqual(config!.maxRetryAfter, 60000 * 5); | ||
const expectedMethods = ['GET', 'HEAD', 'PUT', 'OPTIONS', 'DELETE']; | ||
for (const method of config!.httpMethodsToRetry!) { | ||
assert(expectedMethods.indexOf(method) > -1, 'exected method: $method'); | ||
|
@@ -78,7 +82,8 @@ describe('retry-axios', () => { | |
assert.fail('Expected to throw'); | ||
}); | ||
|
||
it('should retry at least the configured number of times', async () => { | ||
it('should retry at least the configured number of times', async function () { | ||
this.timeout(10000); | ||
const scopes = [ | ||
nock(url).get('/').times(3).reply(500), | ||
nock(url).get('/').reply(200, 'milk'), | ||
|
@@ -88,7 +93,7 @@ describe('retry-axios', () => { | |
const res = await axios(cfg); | ||
assert.strictEqual(res.data, 'milk'); | ||
scopes.forEach(s => s.done()); | ||
}).timeout(10000); | ||
}); | ||
|
||
it('should not retry more than configured', async () => { | ||
const scope = nock(url).get('/').twice().reply(500); | ||
|
@@ -396,4 +401,81 @@ describe('retry-axios', () => { | |
} | ||
assert.fail('Expected to throw'); | ||
}); | ||
|
||
it('should retry with Retry-After header in seconds', async function () { | ||
this.timeout(1000); // Short timeout to trip test if delay longer than expected | ||
const scopes = [ | ||
nock(url).get('/').reply(429, undefined, { | ||
'Retry-After': '5', | ||
}), | ||
nock(url).get('/').reply(200, 'toast'), | ||
]; | ||
interceptorId = rax.attach(); | ||
const {promise, resolve} = invertedPromise(); | ||
const clock = sinon.useFakeTimers({ | ||
shouldAdvanceTime: true, // Otherwise interferes with nock | ||
}); | ||
const axiosPromise = axios({ | ||
url, | ||
raxConfig: { | ||
onRetryAttempt: resolve, | ||
retryDelay: 10000, // Higher default to ensure Retry-After is used | ||
backoffType: 'static', | ||
}, | ||
}); | ||
await promise; | ||
clock.tick(5000); // Advance clock by expected retry delay | ||
const res = await axiosPromise; | ||
assert.strictEqual(res.data, 'toast'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't actually testing if the delays work. I know it's annoying, but could I trouble you to set up a test with a sinon timer, and verify it's doing what we expect? I've had to write similar tests in the past if you're looking for an example: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done using the same pattern - also set a higher default retry delay on the rax config to make sure the Retry-After value is actually being used |
||
scopes.forEach(s => s.done()); | ||
}); | ||
|
||
it('should retry with Retry-After header in http datetime', async function () { | ||
this.timeout(1000); | ||
const scopes = [ | ||
nock(url).get('/').reply(429, undefined, { | ||
'Retry-After': 'Thu, 01 Jan 1970 00:00:05 UTC', | ||
}), | ||
nock(url).get('/').reply(200, 'toast'), | ||
]; | ||
interceptorId = rax.attach(); | ||
const {promise, resolve} = invertedPromise(); | ||
const clock = sinon.useFakeTimers({ | ||
shouldAdvanceTime: true, | ||
}); | ||
const axiosPromise = axios({ | ||
url, | ||
raxConfig: { | ||
onRetryAttempt: resolve, | ||
backoffType: 'static', | ||
retryDelay: 10000, | ||
}, | ||
}); | ||
await promise; | ||
clock.tick(5000); | ||
const res = await axiosPromise; | ||
assert.strictEqual(res.data, 'toast'); | ||
scopes.forEach(s => s.done()); | ||
}); | ||
|
||
it('should not retry if Retry-After greater than maxRetryAfter', async () => { | ||
const scopes = [ | ||
nock(url).get('/').reply(429, undefined, {'Retry-After': '2'}), | ||
nock(url).get('/').reply(200, 'toast'), | ||
]; | ||
interceptorId = rax.attach(); | ||
const cfg: rax.RaxConfig = {url, raxConfig: {maxRetryAfter: 1000}}; | ||
await assert.rejects(axios(cfg)); | ||
assert.strictEqual(scopes[1].isDone(), false); | ||
}); | ||
}); | ||
|
||
function invertedPromise() { | ||
let resolve!: () => void; | ||
let reject!: (err: Error) => void; | ||
const promise = new Promise<void>((innerResolve, innerReject) => { | ||
resolve = innerResolve; | ||
reject = innerReject; | ||
}); | ||
return {promise, resolve, reject}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to change the timeouts to the old function style after getting a weird error on the ci tests - https://github.com/JustinBeckwith/retry-axios/pull/142/checks?sha=f6f6c8d1bbe8b2a6da5301ee457fd6fe0970e121