-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Expand file tree
/
Copy pathnext.fetch.mjs
More file actions
38 lines (32 loc) · 995 Bytes
/
next.fetch.mjs
File metadata and controls
38 lines (32 loc) · 995 Bytes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* @typedef { RequestInit & { maxRetry?: number; delay?: number; }} RetryOptions
*/
const isTimeoutError = e =>
e instanceof Error &&
typeof e.cause === 'object' &&
e.cause !== null &&
'code' in e.cause &&
e.cause.code === 'ETIMEDOUT';
const sleep = ms => new Promise(r => setTimeout(r, ms));
/**
* Does a fetch with retry logic for network errors and timeouts.
*
* @param {string} url
* @param {RetryOptions} [options]
* @returns {Promise<Response>}
*/
export const fetchWithRetry = async (
url,
{ maxRetry = 3, delay = 100, ...options } = {}
) => {
const retries = Math.max(1, Number(maxRetry) || 1);
const backoff = Math.max(0, Number(delay) || 0);
const attemptFetch = attempt =>
fetch(url, { ...options, signal: AbortSignal.timeout(30000) }).catch(e => {
if (attempt === retries || !isTimeoutError(e)) {
throw e;
}
return sleep(backoff * attempt).then(() => attemptFetch(attempt + 1));
});
return attemptFetch(1);
};