diff --git a/.licenses/npm/@actions/cache.dep.yml b/.licenses/npm/@actions/cache.dep.yml index cf83810..b716d1d 100644 Binary files a/.licenses/npm/@actions/cache.dep.yml and b/.licenses/npm/@actions/cache.dep.yml differ diff --git a/README.md b/README.md index fb49b3d..d2aa0fa 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ See ["Caching dependencies to speed up workflows"](https://help.github.com/githu * Fixed tar creation error while trying to create tar with path as `~/` home folder on `ubuntu-latest`. * Fixed zstd failing on amazon linux 2.0 runners * Fixed cache not working with github workspace directory or current directory +* Fixed the download stuck problem by introducing a timeout of 1 hour for cache downloads. Refer [here](https://github.com/actions/cache/blob/v2/README.md) for previous versions diff --git a/RELEASES.md b/RELEASES.md index 0957bf8..59f2c3b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -21,4 +21,7 @@ ### 3.0.6 - Fixed [#809](https://github.com/actions/cache/issues/809) - zstd -d: no such file or directory error -- Fixed [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory \ No newline at end of file +- Fixed [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory + +### 3.0.7 +- Fixed [#810](https://github.com/actions/cache/issues/810) - download stuck issue. A new timeout is introduced in the download process to abort the download if it gets stuck and doesn't finish within an hour. \ No newline at end of file diff --git a/dist/restore/index.js b/dist/restore/index.js index dea79fc..119ca14 100644 --- a/dist/restore/index.js +++ b/dist/restore/index.js @@ -5473,6 +5473,7 @@ const util = __importStar(__webpack_require__(669)); const utils = __importStar(__webpack_require__(15)); const constants_1 = __webpack_require__(931); const requestUtils_1 = __webpack_require__(899); +const abort_controller_1 = __webpack_require__(106); /** * Pipes the body of a HTTP response to a stream * @@ -5656,15 +5657,24 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) { const fd = fs.openSync(archivePath, 'w'); try { downloadProgress.startDisplayTimer(); + const controller = new abort_controller_1.AbortController(); + const abortSignal = controller.signal; while (!downloadProgress.isDone()) { const segmentStart = downloadProgress.segmentOffset + downloadProgress.segmentSize; const segmentSize = Math.min(maxSegmentSize, contentLength - segmentStart); downloadProgress.nextSegment(segmentSize); - const result = yield client.downloadToBuffer(segmentStart, segmentSize, { + const result = yield promiseWithTimeout(options.segmentTimeoutInMs || 3600000, client.downloadToBuffer(segmentStart, segmentSize, { + abortSignal, concurrency: options.downloadConcurrency, onProgress: downloadProgress.onProgress() - }); - fs.writeFileSync(fd, result); + })); + if (result === 'timeout') { + controller.abort(); + throw new Error('Aborting cache download as the download time exceeded the timeout.'); + } + else if (Buffer.isBuffer(result)) { + fs.writeFileSync(fd, result); + } } } finally { @@ -5675,6 +5685,16 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) { }); } exports.downloadCacheStorageSDK = downloadCacheStorageSDK; +const promiseWithTimeout = (timeoutMs, promise) => __awaiter(void 0, void 0, void 0, function* () { + let timeoutHandle; + const timeoutPromise = new Promise(resolve => { + timeoutHandle = setTimeout(() => resolve('timeout'), timeoutMs); + }); + return Promise.race([promise, timeoutPromise]).then(result => { + clearTimeout(timeoutHandle); + return result; + }); +}); //# sourceMappingURL=downloadUtils.js.map /***/ }), @@ -40795,7 +40815,8 @@ function getDownloadOptions(copy) { const result = { useAzureSdk: true, downloadConcurrency: 8, - timeoutInMs: 30000 + timeoutInMs: 30000, + segmentTimeoutInMs: 3600000 }; if (copy) { if (typeof copy.useAzureSdk === 'boolean') { @@ -40807,10 +40828,14 @@ function getDownloadOptions(copy) { if (typeof copy.timeoutInMs === 'number') { result.timeoutInMs = copy.timeoutInMs; } + if (typeof copy.segmentTimeoutInMs === 'number') { + result.segmentTimeoutInMs = copy.segmentTimeoutInMs; + } } core.debug(`Use Azure SDK: ${result.useAzureSdk}`); core.debug(`Download concurrency: ${result.downloadConcurrency}`); core.debug(`Request timeout (ms): ${result.timeoutInMs}`); + core.debug(`Segment download timeout (ms): ${result.segmentTimeoutInMs}`); return result; } exports.getDownloadOptions = getDownloadOptions; diff --git a/dist/save/index.js b/dist/save/index.js index 4236eee..18825d3 100644 --- a/dist/save/index.js +++ b/dist/save/index.js @@ -5473,6 +5473,7 @@ const util = __importStar(__webpack_require__(669)); const utils = __importStar(__webpack_require__(15)); const constants_1 = __webpack_require__(931); const requestUtils_1 = __webpack_require__(899); +const abort_controller_1 = __webpack_require__(106); /** * Pipes the body of a HTTP response to a stream * @@ -5656,15 +5657,24 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) { const fd = fs.openSync(archivePath, 'w'); try { downloadProgress.startDisplayTimer(); + const controller = new abort_controller_1.AbortController(); + const abortSignal = controller.signal; while (!downloadProgress.isDone()) { const segmentStart = downloadProgress.segmentOffset + downloadProgress.segmentSize; const segmentSize = Math.min(maxSegmentSize, contentLength - segmentStart); downloadProgress.nextSegment(segmentSize); - const result = yield client.downloadToBuffer(segmentStart, segmentSize, { + const result = yield promiseWithTimeout(options.segmentTimeoutInMs || 3600000, client.downloadToBuffer(segmentStart, segmentSize, { + abortSignal, concurrency: options.downloadConcurrency, onProgress: downloadProgress.onProgress() - }); - fs.writeFileSync(fd, result); + })); + if (result === 'timeout') { + controller.abort(); + throw new Error('Aborting cache download as the download time exceeded the timeout.'); + } + else if (Buffer.isBuffer(result)) { + fs.writeFileSync(fd, result); + } } } finally { @@ -5675,6 +5685,16 @@ function downloadCacheStorageSDK(archiveLocation, archivePath, options) { }); } exports.downloadCacheStorageSDK = downloadCacheStorageSDK; +const promiseWithTimeout = (timeoutMs, promise) => __awaiter(void 0, void 0, void 0, function* () { + let timeoutHandle; + const timeoutPromise = new Promise(resolve => { + timeoutHandle = setTimeout(() => resolve('timeout'), timeoutMs); + }); + return Promise.race([promise, timeoutPromise]).then(result => { + clearTimeout(timeoutHandle); + return result; + }); +}); //# sourceMappingURL=downloadUtils.js.map /***/ }), @@ -40795,7 +40815,8 @@ function getDownloadOptions(copy) { const result = { useAzureSdk: true, downloadConcurrency: 8, - timeoutInMs: 30000 + timeoutInMs: 30000, + segmentTimeoutInMs: 3600000 }; if (copy) { if (typeof copy.useAzureSdk === 'boolean') { @@ -40807,10 +40828,14 @@ function getDownloadOptions(copy) { if (typeof copy.timeoutInMs === 'number') { result.timeoutInMs = copy.timeoutInMs; } + if (typeof copy.segmentTimeoutInMs === 'number') { + result.segmentTimeoutInMs = copy.segmentTimeoutInMs; + } } core.debug(`Use Azure SDK: ${result.useAzureSdk}`); core.debug(`Download concurrency: ${result.downloadConcurrency}`); core.debug(`Request timeout (ms): ${result.timeoutInMs}`); + core.debug(`Segment download timeout (ms): ${result.segmentTimeoutInMs}`); return result; } exports.getDownloadOptions = getDownloadOptions; diff --git a/package-lock.json b/package-lock.json index 5cb1174..e60f053 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "cache", - "version": "3.0.6", + "version": "3.0.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cache", - "version": "3.0.6", + "version": "3.0.7", "license": "MIT", "dependencies": { - "@actions/cache": "^3.0.1", + "@actions/cache": "^3.0.3", "@actions/core": "^1.7.0", "@actions/exec": "^1.1.1", "@actions/io": "^1.1.2" @@ -36,9 +36,9 @@ } }, "node_modules/@actions/cache": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.1.tgz", - "integrity": "sha512-z4cbwCuzyZHQ3Y3AyQEFb+WQneC1wcOWfjrKxhulGkbXBLiMH/Uga2hknNEgOY16XaDZ7hArYaY3nUxE7IzqLQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.3.tgz", + "integrity": "sha512-kn0pZRQNFRg1IQnW/N7uTNbbLqYalvQW2bmrznn3C34LMY/rSuEmH6Uo69HDh335Q0vKs9kg/jsIarzUBKzEXg==", "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.1", @@ -9533,9 +9533,9 @@ }, "dependencies": { "@actions/cache": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.1.tgz", - "integrity": "sha512-z4cbwCuzyZHQ3Y3AyQEFb+WQneC1wcOWfjrKxhulGkbXBLiMH/Uga2hknNEgOY16XaDZ7hArYaY3nUxE7IzqLQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.0.3.tgz", + "integrity": "sha512-kn0pZRQNFRg1IQnW/N7uTNbbLqYalvQW2bmrznn3C34LMY/rSuEmH6Uo69HDh335Q0vKs9kg/jsIarzUBKzEXg==", "requires": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.1", diff --git a/package.json b/package.json index 8ef01db..aaa1370 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cache", - "version": "3.0.6", + "version": "3.0.7", "private": true, "description": "Cache dependencies and build outputs", "main": "dist/restore/index.js", @@ -23,7 +23,7 @@ "author": "GitHub", "license": "MIT", "dependencies": { - "@actions/cache": "^3.0.1", + "@actions/cache": "^3.0.3", "@actions/core": "^1.7.0", "@actions/exec": "^1.1.1", "@actions/io": "^1.1.2"