From 18e62e1fe0e25b537775120e937f054a4db1f903 Mon Sep 17 00:00:00 2001 From: Dave Hadka Date: Thu, 7 May 2020 21:35:11 -0400 Subject: [PATCH] Add env var for socket timeout --- dist/restore/index.js | 30 ++++++++++++++++++++---------- dist/save/index.js | 30 ++++++++++++++++++++---------- src/cacheHttpClient.ts | 24 +++++++++++++----------- src/constants.ts | 2 +- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/dist/restore/index.js b/dist/restore/index.js index 67707ad..48921bc 100644 --- a/dist/restore/index.js +++ b/dist/restore/index.js @@ -2236,6 +2236,13 @@ function createHttpClient() { const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token); return new http_client_1.HttpClient("actions/cache", [bearerCredentialHandler], getRequestOptions()); } +function parseEnvNumber(key) { + const value = Number(process.env[key]); + if (Number.isNaN(value) || value < 0) { + return undefined; + } + return value; +} function getCacheVersion(compressionMethod) { const components = [core.getInput(constants_1.Inputs.Path, { required: true })].concat(compressionMethod == constants_1.CompressionMethod.Zstd ? [compressionMethod] : []); // Add salt to cache version to support breaking changes in cache entry @@ -2278,14 +2285,16 @@ function pipeResponseToStream(response, output) { }); } function downloadCache(archiveLocation, archivePath) { + var _a; return __awaiter(this, void 0, void 0, function* () { const stream = fs.createWriteStream(archivePath); const httpClient = new http_client_1.HttpClient("actions/cache"); const downloadResponse = yield httpClient.get(archiveLocation); // Abort download if no traffic received over the socket. - downloadResponse.message.socket.setTimeout(constants_1.SocketTimeout, () => { + const socketTimeout = (_a = parseEnvNumber("CACHE_SOCKET_TIMEOUT"), (_a !== null && _a !== void 0 ? _a : constants_1.DefaultSocketTimeout)); + downloadResponse.message.socket.setTimeout(socketTimeout, () => { downloadResponse.message.destroy(); - core.debug(`Aborting download, socket timed out after ${constants_1.SocketTimeout} ms`); + core.debug(`Aborting download, socket timed out after ${socketTimeout} ms`); }); yield pipeResponseToStream(downloadResponse, stream); // Validate download size. @@ -2352,13 +2361,6 @@ function uploadChunk(httpClient, resourceUrl, data, start, end) { throw new Error(`Cache service responded with ${response.message.statusCode} during chunk upload.`); }); } -function parseEnvNumber(key) { - const value = Number(process.env[key]); - if (Number.isNaN(value) || value < 0) { - return undefined; - } - return value; -} function uploadFile(httpClient, cacheId, archivePath) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { @@ -3642,6 +3644,12 @@ class HttpClientResponse { this.message.on('data', (chunk) => { output = Buffer.concat([output, chunk]); }); + this.message.on('aborted', () => { + reject("Request was aborted or closed prematurely"); + }); + this.message.on('timeout', (socket) => { + reject("Request timed out"); + }); this.message.on('end', () => { resolve(output.toString()); }); @@ -3763,6 +3771,7 @@ class HttpClient { let response; while (numTries < maxTries) { response = await this.requestRaw(info, data); + // Check if it's an authentication challenge if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) { let authenticationHandler; @@ -3874,6 +3883,7 @@ class HttpClient { req.on('error', function (err) { // err has statusCode property // res should have headers + console.log(`Caught error on request: ${err}`); handleResult(err, null); }); if (data && typeof (data) === 'string') { @@ -4539,7 +4549,7 @@ var CompressionMethod; // Socket timeout in milliseconds during download. If no traffic is received // over the socket during this period, the socket is destroyed and the download // is aborted. -exports.SocketTimeout = 5000; +exports.DefaultSocketTimeout = 5000; /***/ }), diff --git a/dist/save/index.js b/dist/save/index.js index 3d7a6df..f4b68bf 100644 --- a/dist/save/index.js +++ b/dist/save/index.js @@ -2236,6 +2236,13 @@ function createHttpClient() { const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token); return new http_client_1.HttpClient("actions/cache", [bearerCredentialHandler], getRequestOptions()); } +function parseEnvNumber(key) { + const value = Number(process.env[key]); + if (Number.isNaN(value) || value < 0) { + return undefined; + } + return value; +} function getCacheVersion(compressionMethod) { const components = [core.getInput(constants_1.Inputs.Path, { required: true })].concat(compressionMethod == constants_1.CompressionMethod.Zstd ? [compressionMethod] : []); // Add salt to cache version to support breaking changes in cache entry @@ -2278,14 +2285,16 @@ function pipeResponseToStream(response, output) { }); } function downloadCache(archiveLocation, archivePath) { + var _a; return __awaiter(this, void 0, void 0, function* () { const stream = fs.createWriteStream(archivePath); const httpClient = new http_client_1.HttpClient("actions/cache"); const downloadResponse = yield httpClient.get(archiveLocation); // Abort download if no traffic received over the socket. - downloadResponse.message.socket.setTimeout(constants_1.SocketTimeout, () => { + const socketTimeout = (_a = parseEnvNumber("CACHE_SOCKET_TIMEOUT"), (_a !== null && _a !== void 0 ? _a : constants_1.DefaultSocketTimeout)); + downloadResponse.message.socket.setTimeout(socketTimeout, () => { downloadResponse.message.destroy(); - core.debug(`Aborting download, socket timed out after ${constants_1.SocketTimeout} ms`); + core.debug(`Aborting download, socket timed out after ${socketTimeout} ms`); }); yield pipeResponseToStream(downloadResponse, stream); // Validate download size. @@ -2352,13 +2361,6 @@ function uploadChunk(httpClient, resourceUrl, data, start, end) { throw new Error(`Cache service responded with ${response.message.statusCode} during chunk upload.`); }); } -function parseEnvNumber(key) { - const value = Number(process.env[key]); - if (Number.isNaN(value) || value < 0) { - return undefined; - } - return value; -} function uploadFile(httpClient, cacheId, archivePath) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { @@ -3642,6 +3644,12 @@ class HttpClientResponse { this.message.on('data', (chunk) => { output = Buffer.concat([output, chunk]); }); + this.message.on('aborted', () => { + reject("Request was aborted or closed prematurely"); + }); + this.message.on('timeout', (socket) => { + reject("Request timed out"); + }); this.message.on('end', () => { resolve(output.toString()); }); @@ -3763,6 +3771,7 @@ class HttpClient { let response; while (numTries < maxTries) { response = await this.requestRaw(info, data); + // Check if it's an authentication challenge if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) { let authenticationHandler; @@ -3874,6 +3883,7 @@ class HttpClient { req.on('error', function (err) { // err has statusCode property // res should have headers + console.log(`Caught error on request: ${err}`); handleResult(err, null); }); if (data && typeof (data) === 'string') { @@ -4628,7 +4638,7 @@ var CompressionMethod; // Socket timeout in milliseconds during download. If no traffic is received // over the socket during this period, the socket is destroyed and the download // is aborted. -exports.SocketTimeout = 5000; +exports.DefaultSocketTimeout = 5000; /***/ }), diff --git a/src/cacheHttpClient.ts b/src/cacheHttpClient.ts index c000b7f..2af62a7 100644 --- a/src/cacheHttpClient.ts +++ b/src/cacheHttpClient.ts @@ -11,7 +11,7 @@ import * as fs from "fs"; import * as stream from "stream"; import * as util from "util"; -import { CompressionMethod, Inputs, SocketTimeout } from "./constants"; +import { CompressionMethod, DefaultSocketTimeout, Inputs } from "./constants"; import { ArtifactCacheEntry, CacheOptions, @@ -85,6 +85,14 @@ function createHttpClient(): HttpClient { ); } +function parseEnvNumber(key: string): number | undefined { + const value = Number(process.env[key]); + if (Number.isNaN(value) || value < 0) { + return undefined; + } + return value; +} + export function getCacheVersion(compressionMethod?: CompressionMethod): string { const components = [core.getInput(Inputs.Path, { required: true })].concat( compressionMethod == CompressionMethod.Zstd ? [compressionMethod] : [] @@ -148,10 +156,12 @@ export async function downloadCache( const downloadResponse = await httpClient.get(archiveLocation); // Abort download if no traffic received over the socket. - downloadResponse.message.socket.setTimeout(SocketTimeout, () => { + const socketTimeout = + parseEnvNumber("CACHE_SOCKET_TIMEOUT") ?? DefaultSocketTimeout; + downloadResponse.message.socket.setTimeout(socketTimeout, () => { downloadResponse.message.destroy(); core.debug( - `Aborting download, socket timed out after ${SocketTimeout} ms` + `Aborting download, socket timed out after ${socketTimeout} ms` ); }); @@ -252,14 +262,6 @@ async function uploadChunk( ); } -function parseEnvNumber(key: string): number | undefined { - const value = Number(process.env[key]); - if (Number.isNaN(value) || value < 0) { - return undefined; - } - return value; -} - async function uploadFile( httpClient: HttpClient, cacheId: number, diff --git a/src/constants.ts b/src/constants.ts index d1b1675..e47c7d3 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -32,4 +32,4 @@ export enum CompressionMethod { // Socket timeout in milliseconds during download. If no traffic is received // over the socket during this period, the socket is destroyed and the download // is aborted. -export const SocketTimeout = 5000; +export const DefaultSocketTimeout = 5000;