Skip to content

Commit 87e7f8b

Browse files
authored
replace node-fetch with native fetch (#198408)
* replace node-fetch with native fetch * fix dep version * handle terminated error from fetch * more error handling
1 parent c520c85 commit 87e7f8b

15 files changed

Lines changed: 88 additions & 70 deletions

build/azure-pipelines/common/publish.js

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

build/azure-pipelines/common/publish.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import * as fs from 'fs';
77
import * as path from 'path';
8-
import fetch, { RequestInit } from 'node-fetch';
98
import { Readable } from 'stream';
9+
import type { ReadableStream } from 'stream/web';
1010
import { pipeline } from 'node:stream/promises';
1111
import * as yauzl from 'yauzl';
1212
import * as crypto from 'crypto';
@@ -413,19 +413,23 @@ class State {
413413
}
414414
}
415415

416-
const azdoFetchOptions = { headers: { Authorization: `Bearer ${e('SYSTEM_ACCESSTOKEN')}` }, timeout: 60_000 };
416+
const azdoFetchOptions = { headers: { Authorization: `Bearer ${e('SYSTEM_ACCESSTOKEN')}` } };
417417

418418
async function requestAZDOAPI<T>(path: string): Promise<T> {
419-
const res = await fetch(`${e('BUILDS_API_URL')}${path}?api-version=6.0`, azdoFetchOptions);
419+
const abortController = new AbortController();
420+
const timeout = setTimeout(() => abortController.abort(), 2 * 60 * 1000);
420421

421-
if (!res.ok) {
422-
throw new Error(`Unexpected status code: ${res.status}`);
423-
}
422+
try {
423+
const res = await fetch(`${e('BUILDS_API_URL')}${path}?api-version=6.0`, { ...azdoFetchOptions, signal: abortController.signal });
424424

425-
return await Promise.race([
426-
res.json(),
427-
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 60_000))
428-
]);
425+
if (!res.ok) {
426+
throw new Error(`Unexpected status code: ${res.status}`);
427+
}
428+
429+
return await res.json();
430+
} finally {
431+
clearTimeout(timeout);
432+
}
429433
}
430434

431435
interface Artifact {
@@ -456,16 +460,20 @@ async function getPipelineTimeline(): Promise<Timeline> {
456460
}
457461

458462
async function downloadArtifact(artifact: Artifact, downloadPath: string): Promise<void> {
459-
const res = await fetch(artifact.resource.downloadUrl, azdoFetchOptions);
463+
const abortController = new AbortController();
464+
const timeout = setTimeout(() => abortController.abort(), 6 * 60 * 1000);
460465

461-
if (!res.ok) {
462-
throw new Error(`Unexpected status code: ${res.status}`);
463-
}
466+
try {
467+
const res = await fetch(artifact.resource.downloadUrl, { ...azdoFetchOptions, signal: abortController.signal });
464468

465-
await Promise.race([
466-
pipeline(res.body, fs.createWriteStream(downloadPath)),
467-
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5 * 60 * 1000))
468-
]);
469+
if (!res.ok) {
470+
throw new Error(`Unexpected status code: ${res.status}`);
471+
}
472+
473+
await pipeline(Readable.fromWeb(res.body as ReadableStream), fs.createWriteStream(downloadPath));
474+
} finally {
475+
clearTimeout(timeout);
476+
}
469477
}
470478

471479
async function unzip(packagePath: string, outputPath: string): Promise<string> {

build/azure-pipelines/common/retry.js

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

build/azure-pipelines/common/retry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export async function retry<T>(fn: (attempt: number) => Promise<T>): Promise<T>
1010
try {
1111
return await fn(run);
1212
} catch (err) {
13-
if (!/fetch failed|timeout|TimeoutError|Timeout Error|RestError|Client network socket disconnected|socket hang up|ECONNRESET|CredentialUnavailableError|endpoints_resolution_error|Audience validation failed|end of central directory record signature not found/i.test(err.message)) {
13+
if (!/fetch failed|terminated|aborted|timeout|TimeoutError|Timeout Error|RestError|Client network socket disconnected|socket hang up|ECONNRESET|CredentialUnavailableError|endpoints_resolution_error|Audience validation failed|end of central directory record signature not found/i.test(err.message)) {
1414
throw err;
1515
}
1616

build/lib/builtInExtensionsCG.js

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

build/lib/builtInExtensionsCG.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import fetch from 'node-fetch';
76
import * as fs from 'fs';
87
import * as path from 'path';
98
import * as url from 'url';
@@ -30,7 +29,7 @@ async function downloadExtensionDetails(extension: IExtensionDefinition): Promis
3029
try {
3130
const response = await fetch(`${repositoryContentBaseUrl}/${fileName}`);
3231
if (response.ok) {
33-
return { fileName, body: await response.buffer() };
32+
return { fileName, body: Buffer.from(await response.arrayBuffer()) };
3433
} else if (response.status === 404) {
3534
return { fileName, body: undefined };
3635
} else {

0 commit comments

Comments
 (0)