Skip to content

Commit eac16e9

Browse files
authored
eng - make fetchWithRetry more robust (microsoft#184716)
1 parent 9979f9c commit eac16e9

File tree

2 files changed

+62
-37
lines changed

2 files changed

+62
-37
lines changed

build/lib/gulpRemoteSource.js

Lines changed: 32 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/lib/gulpRemoteSource.ts

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,36 +44,48 @@ export function remote(urls: string[] | string, options: IOptions): es.ThroughSt
4444
}));
4545
}
4646

47-
async function fetchWithRetry(url: string, options: IOptions, retries = 10, retryDelay = 250): Promise<VinylFile> {
47+
async function fetchWithRetry(url: string, options: IOptions, retries = 10, retryDelay = 1000): Promise<VinylFile> {
4848
try {
4949
let startTime = 0;
5050
if (options.verbose) {
5151
log(`Start fetching ${ansiColors.magenta(url)}${retries !== 10 ? `(${10 - retries} retry}` : ''}`);
5252
startTime = new Date().getTime();
5353
}
54-
const response = await fetch(url, options.fetchOptions);
55-
if (options.verbose) {
56-
log(`Fetch completed: Status ${response.status}. Took ${ansiColors.magenta(`${new Date().getTime() - startTime} ms`)}`);
57-
}
58-
if (response.ok && (response.status >= 200 && response.status < 300)) {
59-
// request must be piped out once created, or we'll get this error: "You cannot pipe after data has been emitted from the response."
60-
const contents = options.buffer ? await response.buffer() : response.body.pipe(through2());
61-
return new VinylFile({
62-
cwd: '/',
63-
base: options.base,
64-
path: url,
65-
contents
54+
const controller = new AbortController();
55+
const timeout = setTimeout(() => controller.abort(), 30 * 1000);
56+
try {
57+
const response = await fetch(url, {
58+
...options.fetchOptions,
59+
signal: controller.signal as any /* Typings issue with lib.dom.d.ts */
6660
});
61+
if (options.verbose) {
62+
log(`Fetch completed: Status ${response.status}. Took ${ansiColors.magenta(`${new Date().getTime() - startTime} ms`)}`);
63+
}
64+
if (response.ok && (response.status >= 200 && response.status < 300)) {
65+
// request must be piped out once created, or we'll get this error: "You cannot pipe after data has been emitted from the response."
66+
const contents = options.buffer ? await response.buffer() : response.body.pipe(through2());
67+
if (options.buffer && options.verbose) {
68+
log(`Fetched response body buffer: ${ansiColors.magenta(`${(contents as Buffer).byteLength} bytes`)}`);
69+
}
70+
return new VinylFile({
71+
cwd: '/',
72+
base: options.base,
73+
path: url,
74+
contents
75+
});
76+
}
77+
throw new Error(`Request ${ansiColors.magenta(url)} failed with status code: ${response.status}`);
78+
} finally {
79+
clearTimeout(timeout);
6780
}
68-
throw new Error(`Request ${ansiColors.magenta(url)} failed with status code: ${response.status}`);
6981
} catch (e) {
70-
if (retries > 0) {
71-
await new Promise(c => setTimeout(c, retryDelay));
72-
return fetchWithRetry(url, options, retries - 1, retryDelay * 2);
73-
}
7482
if (options.verbose) {
7583
log(`Fetching ${ansiColors.cyan(url)} failed: ${e}`);
7684
}
85+
if (retries > 0) {
86+
await new Promise(resolve => setTimeout(resolve, retryDelay));
87+
return fetchWithRetry(url, options, retries - 1, retryDelay);
88+
}
7789
throw e;
7890
}
7991
}

0 commit comments

Comments
 (0)