Skip to content

Commit 027a01b

Browse files
authored
BUGFIX-RELEASE: ASSETS-14 [regression] bring back behavior to retry on network timeouts by default (#68)
* ASSETS-14 [regression] bring back behavior to retry on network timeouts * ci re-run * Update index.test.js * ci re-run * less strict flakey test * remove timing constraint * re-run ci
1 parent aaf1b71 commit 027a01b

File tree

2 files changed

+32
-11
lines changed

2 files changed

+32
-11
lines changed

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,13 @@ function checkParameters(retryOptions) {
149149
function shouldRetryOnHttpError(error) {
150150
// special handling for known fetch errors: https://github.com/node-fetch/node-fetch/blob/main/docs/ERROR-HANDLING.md
151151
// retry on all errors originating from Node.js core
152+
// retry on AbortError caused by network timeouts
152153
if (error.name === 'FetchError' && error.type === 'system') {
153154
console.error(`FetchError failed with code: ${error.code}; message: ${error.message}`);
154155
return true;
156+
} else if (error.name === 'AbortError') {
157+
console.error(`AbortError failed with type: ${error.type}; message: ${error.message}`);
158+
return true;
155159
}
156160
return false;
157161
}

test/index.test.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ describe('test `retryInit` function', () => {
5252
delete process.env.NODE_FETCH_RETRY_INITIAL_WAIT;
5353
delete process.env.NODE_FETCH_RETRY_FORCE_TIMEOUT;
5454
});
55+
5556
it('no params, use default values', () => {
5657
const rewiredFetchRetry = rewire('../index');
5758
const retryInit = rewiredFetchRetry.__get__('retryInit');
@@ -180,6 +181,7 @@ describe('test `retryInit` function', () => {
180181
assert.strictEqual(retryOptions.retryOnHttpResponse({ status: 400 }), false);
181182
assert.strictEqual(retryOptions.socketTimeout, 1500); // gets set to half the retryMaxDuration
182183
});
184+
183185
it('socket timeout is larger than retry max duration but `forceSocketTimeout` is true', () => {
184186
const rewiredFetchRetry = rewire('../index');
185187
const retryInit = rewiredFetchRetry.__get__('retryInit');
@@ -217,6 +219,7 @@ describe('test `retryInit` function', () => {
217219
assert.strictEqual(retryOptions.retryOnHttpResponse({ status: 500 }), true);
218220
assert.strictEqual(retryOptions.retryOnHttpResponse({ status: 400 }), false);
219221
});
222+
220223
it('custom retry on http response', () => {
221224
const rewiredFetchRetry = rewire('../index');
222225
const retryInit = rewiredFetchRetry.__get__('retryInit');
@@ -661,7 +664,6 @@ describe('test fetch retry', () => {
661664

662665
it("verifies handling of socket timeout when socket times out - use retryMax as timeout value (after first failure)", async () => {
663666
const socketTimeout = 50000;
664-
665667
console.log("!! Test http server ----------");
666668
// The test needs to be able to control the server socket
667669
// (which nock or whatever-http-mock can't).
@@ -849,33 +851,48 @@ describe('test fetch retry on http errors (throw exceptions)', () => {
849851
message: 'something awful happened',
850852
code: '503',
851853
});
852-
const timer = new Timer();
853854
try {
854855
await fetch(`${FAKE_BASE_URL}${FAKE_PATH}`, { method: 'GET', retryOptions: { retryMaxDuration: 2 } });
855856
assert.fail("Should have thrown an error!");
856857
} catch (e) {
857858
assert(e.message.includes("network timeout"));
858859
assert(e.type === "request-timeout");
859860
}
860-
console.log(`ellapsed: ${timer.ellapsed}`);
861-
assert.ok(timer.isBetween(1, 100), "Should have taken approximately 10ms");
861+
assert(nock.isDone());
862862
});
863-
it('test network timeout [mocked]', async () => {
863+
it('test network timeout is retried once [mocked]', async () => {
864864
nock(FAKE_BASE_URL)
865865
.get(FAKE_PATH)
866-
.delayConnection(5000) // 2 seconds
866+
.delayConnection(5000) // 5 seconds
867+
.reply(200);
868+
nock(FAKE_BASE_URL)
869+
.get(FAKE_PATH)
870+
.reply(200);
871+
872+
const response = await fetch(`${FAKE_BASE_URL}${FAKE_PATH}`, { method: 'GET', retryOptions: { retryMaxDuration: 2000 } });
873+
assert(nock.isDone());
874+
assert.strictEqual(response.statusText, 'OK');
875+
assert.strictEqual(response.status, 200);
876+
});
877+
it('test network timeout again after it is retried once [mocked]', async () => {
878+
nock(FAKE_BASE_URL)
879+
.get(FAKE_PATH)
880+
.delayConnection(1000) // 5 seconds
881+
.reply(200);
882+
nock(FAKE_BASE_URL)
883+
.get(FAKE_PATH)
884+
.delayConnection(1000) // 5 seconds
867885
.reply(200);
868-
const timer = new Timer();
869886
try {
870-
await fetch(`${FAKE_BASE_URL}${FAKE_PATH}`, { method: 'GET', retryOptions: { retryMaxDuration: 2000 } });
887+
await fetch(`${FAKE_BASE_URL}${FAKE_PATH}`, { method: 'GET', retryOptions: { retryMaxDuration: 1000 } });
871888
assert.fail("Should have thrown an error!");
872889
} catch (e) {
873890
assert(e.message.includes("network timeout"));
874891
assert(e.type === "request-timeout");
892+
assert(nock.isDone());
875893
}
876-
console.log(`ellapsed: ${timer.ellapsed}`);
877-
assert.ok(timer.isBetween(1000, 1500), "Should have taken approximately 1s");
878894
});
895+
879896
it('timeout retrying on error ECONNRESET', async () => {
880897
const systemError = new FetchError('socket hang up', 'system', {
881898
code: 'ECONNRESET'
@@ -997,4 +1014,4 @@ describe('test fetch retry on http errors (throw exceptions)', () => {
9971014
assert.strictEqual(response.statusText, 'OK');
9981015
assert.strictEqual(response.status, 200);
9991016
});
1000-
});
1017+
});

0 commit comments

Comments
 (0)