Skip to content

Commit b7e6493

Browse files
[NodeToolV0/UseNodeV1] - Add inputs to manage retries and delays (#19243)
* [NodeToolV0/UseNodeV1] - Add inputs to manage retries and delays -- Added retryCountOnDownloadFails input -- Added delayBetweenRetries input * [NodeToolV0/UseNodeV1] - Add inputs to manage retries and delays -- Added retryCountOnDownloadFails input -- Added delayBetweenRetries input
1 parent c10f72b commit b7e6493

File tree

29 files changed

+380
-101
lines changed

29 files changed

+380
-101
lines changed

Tasks/NodeToolV0/Strings/resources.resjson/en-US/resources.resjson

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
"loc.input.help.force32bit": "Installs the x86 version of Node regardless of the CPU architecture of the agent.",
1616
"loc.input.label.nodejsMirror": "Set source for Node.js binaries",
1717
"loc.input.help.nodejsMirror": "Use an alternative installation mirror when sourcing the Node.js binaries.",
18+
"loc.input.label.retryCountOnDownloadFails": "Set retry count when nodes downloads failed",
19+
"loc.input.help.retryCountOnDownloadFails": "Use this option when the task failed to download node binaries from the mirror. The task will retry to download the binaries for the specified times.",
20+
"loc.input.label.delayBetweenRetries": "Set delay between retries",
21+
"loc.input.help.delayBetweenRetries": "Use this option to set the delay between retries in milliseconds. The default value is 1000 milliseconds.",
1822
"loc.messages.ToolFailed": "Tool install failed: %s",
1923
"loc.messages.TryRosetta": "Unable to find Node for platform %s and architecture %s. Trying to install with Rosetta2",
2024
"loc.messages.NodeVersionNotFound": "Unable to find Node version %s for platform %s and architecture %s.",

Tasks/NodeToolV0/nodetool.ts

+19-12
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ async function run() {
1717
let versionSpecInput = taskLib.getInput('versionSpec', versionSource == 'spec');
1818
let versionFilePathInput = taskLib.getInput('versionFilePath', versionSource == 'fromFile');
1919
let nodejsMirror = taskLib.getInput('nodejsMirror', false);
20+
const retryCountOnDownloadFails = taskLib.getInput('retryCountOnDownloadFails', false) || "5";
21+
const delayBetweenRetries = taskLib.getInput('delayBetweenRetries', false) || "1000";
2022
let versionSpec = getNodeVersion(versionSource, versionSpecInput, versionFilePathInput);
2123
let checkLatest: boolean = taskLib.getBoolInput('checkLatest', false);
22-
await getNode(versionSpec, checkLatest, nodejsMirror.replace(/\/$/, ''));
24+
await getNode(versionSpec, checkLatest, nodejsMirror.replace(/\/$/, ''), parseInt(retryCountOnDownloadFails), parseInt(delayBetweenRetries));
2325
telemetry.emitTelemetry('TaskHub', 'NodeToolV0', { versionSource, versionSpec, checkLatest, force32bit });
2426
}
2527
catch (error) {
@@ -52,7 +54,7 @@ interface INodeVersion {
5254
// toolPath = cacheDir
5355
// PATH = cacheDir + PATH
5456
//
55-
async function getNode(versionSpec: string, checkLatest: boolean, nodejsMirror: string) {
57+
async function getNode(versionSpec: string, checkLatest: boolean, nodejsMirror: string, retryCountOnDownloadFails: number, delayBetweenRetries: number) {
5658
let installedArch = osArch;
5759
if (toolLib.isExplicitVersion(versionSpec)) {
5860
checkLatest = false; // check latest doesn't make sense when explicit version
@@ -96,7 +98,7 @@ async function getNode(versionSpec: string, checkLatest: boolean, nodejsMirror:
9698

9799
if (!toolPath) {
98100
// download, extract, cache
99-
toolPath = await acquireNode(version, installedArch, nodejsMirror);
101+
toolPath = await acquireNode(version, installedArch, nodejsMirror, retryCountOnDownloadFails, delayBetweenRetries);
100102
}
101103
}
102104

@@ -147,7 +149,7 @@ async function queryLatestMatch(versionSpec: string, installedArch: string, node
147149
return nodeVersions.find(v => v.semanticVersion === latestVersion).version;
148150
}
149151

150-
async function acquireNode(version: string, installedArch: string, nodejsMirror: string): Promise<string> {
152+
async function acquireNode(version: string, installedArch: string, nodejsMirror: string, retryCountOnDownloadFails: number, delayBetweenRetries: number): Promise<string> {
151153
//
152154
// Download - a tool installer intimately knows how to get the tool (and construct urls)
153155
//
@@ -166,10 +168,12 @@ async function acquireNode(version: string, installedArch: string, nodejsMirror:
166168
let downloadPath: string;
167169

168170
try {
169-
downloadPath = await toolLib.downloadToolWithRetries(downloadUrl);
171+
console.log("Aquiring Node called")
172+
console.log("Retry count on download fails: " + retryCountOnDownloadFails + " Retry delay: " + delayBetweenRetries + "ms")
173+
downloadPath = await toolLib.downloadToolWithRetries(downloadUrl, null, null, null, retryCountOnDownloadFails, delayBetweenRetries);
170174
} catch (err) {
171175
if (isWin32 && err['httpStatusCode'] == 404) {
172-
return await acquireNodeFromFallbackLocation(version, nodejsMirror);
176+
return await acquireNodeFromFallbackLocation(version, nodejsMirror, retryCountOnDownloadFails, delayBetweenRetries);
173177
}
174178

175179
throw err;
@@ -213,19 +217,22 @@ async function acquireNode(version: string, installedArch: string, nodejsMirror:
213217
// This method attempts to download and cache the resources from these alternative locations.
214218
// Note also that the files are normally zipped but in this case they are just an exe
215219
// and lib file in a folder, not zipped.
216-
async function acquireNodeFromFallbackLocation(version: string, nodejsMirror: string): Promise<string> {
220+
async function acquireNodeFromFallbackLocation(version: string, nodejsMirror: string, retryCountOnDownloadFails: number, delayBetweenRetries: number): Promise<string> {
217221
// Create temporary folder to download in to
218222
let tempDownloadFolder: string = 'temp_' + Math.floor(Math.random() * 2000000000);
219223
let tempDir: string = path.join(taskLib.getVariable('agent.tempDirectory'), tempDownloadFolder);
220224
taskLib.mkdirP(tempDir);
221225
let exeUrl: string;
222226
let libUrl: string;
227+
console.log("Aquiring Node from callback called")
228+
console.log("Retry count on download fails: " + retryCountOnDownloadFails + " Retry delay: " + delayBetweenRetries + "ms")
229+
223230
try {
224231
exeUrl = `${nodejsMirror}/v${version}/win-${osArch}/node.exe`;
225232
libUrl = `${nodejsMirror}/v${version}/win-${osArch}/node.lib`;
226-
227-
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, "node.exe"));
228-
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, "node.lib"));
233+
234+
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, "node.exe"), null, null, retryCountOnDownloadFails, delayBetweenRetries);
235+
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, "node.lib"), null, null, retryCountOnDownloadFails, delayBetweenRetries);
229236
}
230237
catch (err) {
231238
if (err['httpStatusCode'] &&
@@ -234,8 +241,8 @@ async function acquireNodeFromFallbackLocation(version: string, nodejsMirror: st
234241
exeUrl = `${nodejsMirror}/v${version}/node.exe`;
235242
libUrl = `${nodejsMirror}/v${version}/node.lib`;
236243

237-
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, "node.exe"));
238-
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, "node.lib"));
244+
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, "node.exe"), null, null, retryCountOnDownloadFails, delayBetweenRetries);
245+
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, "node.lib"), null, null, retryCountOnDownloadFails, delayBetweenRetries);
239246
}
240247
else {
241248
throw err;

Tasks/NodeToolV0/task.json

+19-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"version": {
1515
"Major": 0,
1616
"Minor": 231,
17-
"Patch": 0
17+
"Patch": 2
1818
},
1919
"satisfies": [
2020
"Node",
@@ -82,6 +82,24 @@
8282
"required": false,
8383
"groupName": "advanced",
8484
"helpMarkDown": "Use an alternative installation mirror when sourcing the Node.js binaries."
85+
},
86+
{
87+
"name": "retryCountOnDownloadFails",
88+
"type": "string",
89+
"label": "Set retry count when nodes downloads failed",
90+
"defaultValue": "5",
91+
"required": false,
92+
"groupName": "advanced",
93+
"helpMarkDown": "Use this option when the task failed to download node binaries from the mirror. The task will retry to download the binaries for the specified times."
94+
},
95+
{
96+
"name": "delayBetweenRetries",
97+
"type": "string",
98+
"label": "Set delay between retries",
99+
"defaultValue": "1000",
100+
"required": false,
101+
"groupName": "advanced",
102+
"helpMarkDown": "Use this option to set the delay between retries in milliseconds. The default value is 1000 milliseconds."
85103
}
86104
],
87105
"execution": {

Tasks/NodeToolV0/task.loc.json

+19-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"version": {
1515
"Major": 0,
1616
"Minor": 231,
17-
"Patch": 0
17+
"Patch": 2
1818
},
1919
"satisfies": [
2020
"Node",
@@ -82,6 +82,24 @@
8282
"required": false,
8383
"groupName": "advanced",
8484
"helpMarkDown": "ms-resource:loc.input.help.nodejsMirror"
85+
},
86+
{
87+
"name": "retryCountOnDownloadFails",
88+
"type": "string",
89+
"label": "ms-resource:loc.input.label.retryCountOnDownloadFails",
90+
"defaultValue": "5",
91+
"required": false,
92+
"groupName": "advanced",
93+
"helpMarkDown": "ms-resource:loc.input.help.retryCountOnDownloadFails"
94+
},
95+
{
96+
"name": "delayBetweenRetries",
97+
"type": "string",
98+
"label": "ms-resource:loc.input.label.delayBetweenRetries",
99+
"defaultValue": "1000",
100+
"required": false,
101+
"groupName": "advanced",
102+
"helpMarkDown": "ms-resource:loc.input.help.delayBetweenRetries"
85103
}
86104
],
87105
"execution": {

Tasks/UseNodeV1/Strings/resources.resjson/en-US/resources.resjson

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
"loc.input.help.checkLatest": "Always checks online for the latest available version that satisfies the version spec. This is typically false unless you have a specific scenario to always get latest. This will cause it to incur download costs when potentially not necessary, especially with the hosted build pool.",
1010
"loc.input.label.force32bit": "Use 32 bit version on x64 agents",
1111
"loc.input.help.force32bit": "Installs the x86 version of Node regardless of the CPU architecture of the agent.",
12+
"loc.input.label.retryCountOnDownloadFails": "Set retry count when nodes downloads failed",
13+
"loc.input.help.retryCountOnDownloadFails": "Use this option when the task failed to download node binaries from the mirror. The task will retry to download the binaries for the specified times.",
14+
"loc.input.label.delayBetweenRetries": "Set delay between retries",
15+
"loc.input.help.delayBetweenRetries": "Use this option to set the delay between retries in milliseconds. The default value is 1000 milliseconds.",
1216
"loc.messages.ToolFailed": "Node install failed: %s",
1317
"loc.messages.TryRosetta": "Unable to find Node for platform %s and architecture %s. Trying to install with Rosetta2",
1418
"loc.messages.NodeVersionNotFound": "Unable to find Node version %s for platform %s and architecture %s.",

Tasks/UseNodeV1/installer.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface INodeVersion {
3737
// toolPath = cacheDir
3838
// PATH = cacheDir + PATH
3939
//
40-
export async function getNode(versionSpec: string, checkLatest: boolean) {
40+
export async function getNode(versionSpec: string, checkLatest: boolean, retryCountOnDownloadFails: number, delayBetweenRetries: number) {
4141
let installedArch = osArch;
4242

4343
if (toolLib.isExplicitVersion(versionSpec)) {
@@ -82,7 +82,7 @@ export async function getNode(versionSpec: string, checkLatest: boolean) {
8282

8383
if (!toolPath) {
8484
// download, extract, cache
85-
toolPath = await acquireNode(version, installedArch);
85+
toolPath = await acquireNode(version, installedArch, retryCountOnDownloadFails, delayBetweenRetries);
8686
}
8787
}
8888

@@ -143,7 +143,7 @@ async function queryLatestMatch(versionSpec: string, installedArch: string): Pro
143143
return nodeVersions.find(v => v.semanticVersion === latestVersion).version;
144144
}
145145

146-
async function acquireNode(version: string, installedArch: string): Promise<string> {
146+
async function acquireNode(version: string, installedArch: string, retryCountOnDownloadFails: number, delayBetweenRetries: number): Promise<string> {
147147
//
148148
// Download - a tool installer intimately knows how to get the tool (and construct urls)
149149
//
@@ -162,10 +162,12 @@ async function acquireNode(version: string, installedArch: string): Promise<stri
162162
let downloadPath: string;
163163

164164
try {
165-
downloadPath = await toolLib.downloadToolWithRetries(downloadUrl);
165+
console.log("Aquiring Node called")
166+
console.log("Retry count on download fails: " + retryCountOnDownloadFails + " Retry delay: " + delayBetweenRetries + "ms")
167+
downloadPath = await toolLib.downloadToolWithRetries(downloadUrl, null, null, null, retryCountOnDownloadFails, delayBetweenRetries);
166168
} catch (err) {
167169
if (isWin32 && err['httpStatusCode'] == 404) {
168-
return await acquireNodeFromFallbackLocation(version);
170+
return await acquireNodeFromFallbackLocation(version, retryCountOnDownloadFails, delayBetweenRetries);
169171
}
170172

171173
throw err;
@@ -208,29 +210,31 @@ async function acquireNode(version: string, installedArch: string): Promise<stri
208210
// This method attempts to download and cache the resources from these alternative locations.
209211
// Note also that the files are normally zipped but in this case they are just an exe
210212
// and lib file in a folder, not zipped.
211-
async function acquireNodeFromFallbackLocation(version: string): Promise<string> {
213+
async function acquireNodeFromFallbackLocation(version: string, retryCountOnDownloadFails: number, delayBetweenRetries: number): Promise<string> {
212214
// Create temporary folder to download in to
213215
const tempDownloadFolder: string = 'temp_' + Math.floor(Math.random() * 2e9);
214216
const tempDir: string = path.join(taskLib.getVariable('agent.tempDirectory'), tempDownloadFolder);
215217
taskLib.mkdirP(tempDir);
216218

217219
let exeUrl: string;
218220
let libUrl: string;
221+
console.log("Aquiring Node from callback called")
222+
console.log("Retry count on download fails: " + retryCountOnDownloadFails + " Retry delay: " + delayBetweenRetries + "ms")
219223
try {
220224
exeUrl = `https://nodejs.org/dist/v${version}/win-${osArch}/node.exe`;
221225
libUrl = `https://nodejs.org/dist/v${version}/win-${osArch}/node.lib`;
222226

223-
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, 'node.exe'));
224-
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, 'node.lib'));
227+
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, 'node.exe'), null, null, retryCountOnDownloadFails, delayBetweenRetries);
228+
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, 'node.lib'), null, null, retryCountOnDownloadFails, delayBetweenRetries);
225229
}
226230
catch (err) {
227231
if (err['httpStatusCode'] &&
228232
err['httpStatusCode'] === '404') {
229233
exeUrl = `https://nodejs.org/dist/v${version}/node.exe`;
230234
libUrl = `https://nodejs.org/dist/v${version}/node.lib`;
231235

232-
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, 'node.exe'));
233-
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, 'node.lib'));
236+
await toolLib.downloadToolWithRetries(exeUrl, path.join(tempDir, 'node.exe'), null, null, retryCountOnDownloadFails, delayBetweenRetries);
237+
await toolLib.downloadToolWithRetries(libUrl, path.join(tempDir, 'node.lib'), null, null, retryCountOnDownloadFails, delayBetweenRetries);
234238
}
235239
else {
236240
throw err;

Tasks/UseNodeV1/task.json

+19-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"version": {
1818
"Major": 1,
1919
"Minor": 231,
20-
"Patch": 0
20+
"Patch": 2
2121
},
2222
"satisfies": [
2323
"Node",
@@ -50,6 +50,24 @@
5050
"defaultValue": "false",
5151
"required": false,
5252
"helpMarkDown": "Installs the x86 version of Node regardless of the CPU architecture of the agent."
53+
},
54+
{
55+
"name": "retryCountOnDownloadFails",
56+
"type": "string",
57+
"label": "Set retry count when nodes downloads failed",
58+
"defaultValue": "5",
59+
"required": false,
60+
"groupName": "advanced",
61+
"helpMarkDown": "Use this option when the task failed to download node binaries from the mirror. The task will retry to download the binaries for the specified times."
62+
},
63+
{
64+
"name": "delayBetweenRetries",
65+
"type": "string",
66+
"label": "Set delay between retries",
67+
"defaultValue": "1000",
68+
"required": false,
69+
"groupName": "advanced",
70+
"helpMarkDown": "Use this option to set the delay between retries in milliseconds. The default value is 1000 milliseconds."
5371
}
5472
],
5573
"execution": {

Tasks/UseNodeV1/task.loc.json

+19-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"version": {
1818
"Major": 1,
1919
"Minor": 231,
20-
"Patch": 0
20+
"Patch": 2
2121
},
2222
"satisfies": [
2323
"Node",
@@ -50,6 +50,24 @@
5050
"defaultValue": "false",
5151
"required": false,
5252
"helpMarkDown": "ms-resource:loc.input.help.force32bit"
53+
},
54+
{
55+
"name": "retryCountOnDownloadFails",
56+
"type": "string",
57+
"label": "ms-resource:loc.input.label.retryCountOnDownloadFails",
58+
"defaultValue": "5",
59+
"required": false,
60+
"groupName": "advanced",
61+
"helpMarkDown": "ms-resource:loc.input.help.retryCountOnDownloadFails"
62+
},
63+
{
64+
"name": "delayBetweenRetries",
65+
"type": "string",
66+
"label": "ms-resource:loc.input.label.delayBetweenRetries",
67+
"defaultValue": "1000",
68+
"required": false,
69+
"groupName": "advanced",
70+
"helpMarkDown": "ms-resource:loc.input.help.delayBetweenRetries"
5371
}
5472
],
5573
"execution": {

Tasks/UseNodeV1/usenode.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ async function run() {
2121
//
2222
taskLib.setResourcePath(path.join(__dirname, 'task.json'));
2323
const version = taskLib.getInput('version', false);
24+
const retryCountOnDownloadFails = taskLib.getInput('retryCountOnDownloadFails', false) || "5";
25+
const delayBetweenRetries = taskLib.getInput('delayBetweenRetries', false) || "1000";
2426
if (version) {
2527
const checkLatest: boolean = taskLib.getBoolInput('checkLatest', false);
26-
await installer.getNode(version, checkLatest);
28+
await installer.getNode(version, checkLatest, parseInt(retryCountOnDownloadFails), parseInt(delayBetweenRetries));
2729
}
2830

2931
const proxyCfg: taskLib.ProxyConfiguration = taskLib.getHttpProxyConfiguration();

_generated/NodeToolV0.versionmap.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Default|0.231.0
2-
Node20-225|0.231.1
1+
Default|0.231.2
2+
Node20-225|0.231.3

_generated/NodeToolV0/Strings/resources.resjson/en-US/resources.resjson

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
"loc.input.help.force32bit": "Installs the x86 version of Node regardless of the CPU architecture of the agent.",
1616
"loc.input.label.nodejsMirror": "Set source for Node.js binaries",
1717
"loc.input.help.nodejsMirror": "Use an alternative installation mirror when sourcing the Node.js binaries.",
18+
"loc.input.label.retryCountOnDownloadFails": "Set retry count when nodes downloads failed",
19+
"loc.input.help.retryCountOnDownloadFails": "Use this option when the task failed to download node binaries from the mirror. The task will retry to download the binaries for the specified times.",
20+
"loc.input.label.delayBetweenRetries": "Set delay between retries",
21+
"loc.input.help.delayBetweenRetries": "Use this option to set the delay between retries in milliseconds. The default value is 1000 milliseconds.",
1822
"loc.messages.ToolFailed": "Tool install failed: %s",
1923
"loc.messages.TryRosetta": "Unable to find Node for platform %s and architecture %s. Trying to install with Rosetta2",
2024
"loc.messages.NodeVersionNotFound": "Unable to find Node version %s for platform %s and architecture %s.",

0 commit comments

Comments
 (0)