Force exit of process if a timeout has occurred
This commit is contained in:
parent
7c9e85e249
commit
d6f6ef4b0b
6 changed files with 72 additions and 7 deletions
2
lib/analyze-action.js
generated
2
lib/analyze-action.js
generated
|
|
@ -42,6 +42,7 @@ const repository_1 = require("./repository");
|
||||||
const trap_caching_1 = require("./trap-caching");
|
const trap_caching_1 = require("./trap-caching");
|
||||||
const upload_lib = __importStar(require("./upload-lib"));
|
const upload_lib = __importStar(require("./upload-lib"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
|
const util_1 = require("./util");
|
||||||
// eslint-disable-next-line import/no-commonjs
|
// eslint-disable-next-line import/no-commonjs
|
||||||
const pkg = require("../package.json");
|
const pkg = require("../package.json");
|
||||||
async function sendStatusReport(startedAt, config, stats, error, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, logger) {
|
async function sendStatusReport(startedAt, config, stats, error, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, logger) {
|
||||||
|
|
@ -238,6 +239,7 @@ async function runWrapper() {
|
||||||
core.setFailed(`analyze action failed: ${error}`);
|
core.setFailed(`analyze action failed: ${error}`);
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
await (0, util_1.checkForTimeout)();
|
||||||
}
|
}
|
||||||
void runWrapper();
|
void runWrapper();
|
||||||
//# sourceMappingURL=analyze-action.js.map
|
//# sourceMappingURL=analyze-action.js.map
|
||||||
File diff suppressed because one or more lines are too long
35
lib/util.js
generated
35
lib/util.js
generated
|
|
@ -22,7 +22,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isHostedRunner = exports.withTimeout = exports.tryGetFolderBytes = exports.isGoExtractionReconciliationEnabled = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.checkActionVersion = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.isActions = exports.getMode = exports.enrichEnvironment = exports.initializeEnvironment = exports.EnvVar = exports.Mode = exports.assertNever = exports.getGitHubAuth = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DID_AUTOBUILD_GO_ENV_VAR_NAME = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.isGoExtractionReconciliationEnabled = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.checkActionVersion = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.isActions = exports.getMode = exports.enrichEnvironment = exports.initializeEnvironment = exports.EnvVar = exports.Mode = exports.assertNever = exports.getGitHubAuth = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DID_AUTOBUILD_GO_ENV_VAR_NAME = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
||||||
|
exports.isHostedRunner = void 0;
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const os = __importStar(require("os"));
|
const os = __importStar(require("os"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
|
|
@ -719,13 +720,21 @@ async function tryGetFolderBytes(cacheDir, logger) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.tryGetFolderBytes = tryGetFolderBytes;
|
exports.tryGetFolderBytes = tryGetFolderBytes;
|
||||||
|
let hadTimeout = false;
|
||||||
/**
|
/**
|
||||||
* Run a promise for a given amount of time, and if it doesn't resolve within
|
* Run a promise for a given amount of time, and if it doesn't resolve within
|
||||||
* that time, call the provided callback and then return undefined.
|
* that time, call the provided callback and then return undefined. Due to the
|
||||||
|
* limitation outlined below, using this helper function is not recommended
|
||||||
|
* unless there is no other option for adding a timeout (e.g. the code that
|
||||||
|
* would need the timeout added is an external library).
|
||||||
*
|
*
|
||||||
* Important: This does NOT cancel the original promise, so that promise will
|
* Important: This does NOT cancel the original promise, so that promise will
|
||||||
* continue in the background even after the timeout has expired. If the
|
* continue in the background even after the timeout has expired. If the
|
||||||
* original promise hangs, then this will prevent the process terminating.
|
* original promise hangs, then this will prevent the process terminating.
|
||||||
|
* If a timeout has occurred then the global hadTimeout variable will get set
|
||||||
|
* to true, and the caller is responsible for forcing the process to exit
|
||||||
|
* if this is the case by calling the `checkForTimeout` function at the end
|
||||||
|
* of execution.
|
||||||
*
|
*
|
||||||
* @param timeoutMs The timeout in milliseconds.
|
* @param timeoutMs The timeout in milliseconds.
|
||||||
* @param promise The promise to run.
|
* @param promise The promise to run.
|
||||||
|
|
@ -741,14 +750,34 @@ async function withTimeout(timeoutMs, promise, onTimeout) {
|
||||||
};
|
};
|
||||||
const timeout = new Promise((resolve) => {
|
const timeout = new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!finished)
|
if (!finished) {
|
||||||
|
// Workaround: While the promise racing below will allow the main code
|
||||||
|
// to continue, the process won't normally exit until the asynchronous
|
||||||
|
// task in the background has finished. We set this variable to force
|
||||||
|
// an exit at the end of our code when `checkForTimeout` is called.
|
||||||
|
hadTimeout = true;
|
||||||
onTimeout();
|
onTimeout();
|
||||||
|
}
|
||||||
resolve(undefined);
|
resolve(undefined);
|
||||||
}, timeoutMs);
|
}, timeoutMs);
|
||||||
});
|
});
|
||||||
return await Promise.race([mainTask(), timeout]);
|
return await Promise.race([mainTask(), timeout]);
|
||||||
}
|
}
|
||||||
exports.withTimeout = withTimeout;
|
exports.withTimeout = withTimeout;
|
||||||
|
/**
|
||||||
|
* Check if the global hadTimeout variable has been set, and if so then
|
||||||
|
* exit the process to ensure any background tasks that are still running
|
||||||
|
* are killed. This should be called at the end of execution if the
|
||||||
|
* `withTimeout` function has been used.
|
||||||
|
*/
|
||||||
|
async function checkForTimeout() {
|
||||||
|
if (hadTimeout === true) {
|
||||||
|
core.info("A timeout occurred, force exiting the process after 30 seconds to prevent hanging.");
|
||||||
|
await delay(30000);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.checkForTimeout = checkForTimeout;
|
||||||
/**
|
/**
|
||||||
* This function implements a heuristic to determine whether the
|
* This function implements a heuristic to determine whether the
|
||||||
* runner we are on is hosted by GitHub. It does this by checking
|
* runner we are on is hosted by GitHub. It does this by checking
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -27,6 +27,7 @@ import { getTotalCacheSize, uploadTrapCaches } from "./trap-caching";
|
||||||
import * as upload_lib from "./upload-lib";
|
import * as upload_lib from "./upload-lib";
|
||||||
import { UploadResult } from "./upload-lib";
|
import { UploadResult } from "./upload-lib";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
|
import { checkForTimeout } from "./util";
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-commonjs
|
// eslint-disable-next-line import/no-commonjs
|
||||||
const pkg = require("../package.json");
|
const pkg = require("../package.json");
|
||||||
|
|
@ -402,6 +403,7 @@ async function runWrapper() {
|
||||||
core.setFailed(`analyze action failed: ${error}`);
|
core.setFailed(`analyze action failed: ${error}`);
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
await checkForTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void runWrapper();
|
void runWrapper();
|
||||||
|
|
|
||||||
36
src/util.ts
36
src/util.ts
|
|
@ -858,13 +858,22 @@ export async function tryGetFolderBytes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hadTimeout = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a promise for a given amount of time, and if it doesn't resolve within
|
* Run a promise for a given amount of time, and if it doesn't resolve within
|
||||||
* that time, call the provided callback and then return undefined.
|
* that time, call the provided callback and then return undefined. Due to the
|
||||||
|
* limitation outlined below, using this helper function is not recommended
|
||||||
|
* unless there is no other option for adding a timeout (e.g. the code that
|
||||||
|
* would need the timeout added is an external library).
|
||||||
*
|
*
|
||||||
* Important: This does NOT cancel the original promise, so that promise will
|
* Important: This does NOT cancel the original promise, so that promise will
|
||||||
* continue in the background even after the timeout has expired. If the
|
* continue in the background even after the timeout has expired. If the
|
||||||
* original promise hangs, then this will prevent the process terminating.
|
* original promise hangs, then this will prevent the process terminating.
|
||||||
|
* If a timeout has occurred then the global hadTimeout variable will get set
|
||||||
|
* to true, and the caller is responsible for forcing the process to exit
|
||||||
|
* if this is the case by calling the `checkForTimeout` function at the end
|
||||||
|
* of execution.
|
||||||
*
|
*
|
||||||
* @param timeoutMs The timeout in milliseconds.
|
* @param timeoutMs The timeout in milliseconds.
|
||||||
* @param promise The promise to run.
|
* @param promise The promise to run.
|
||||||
|
|
@ -884,7 +893,14 @@ export async function withTimeout<T>(
|
||||||
};
|
};
|
||||||
const timeout: Promise<undefined> = new Promise((resolve) => {
|
const timeout: Promise<undefined> = new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!finished) onTimeout();
|
if (!finished) {
|
||||||
|
// Workaround: While the promise racing below will allow the main code
|
||||||
|
// to continue, the process won't normally exit until the asynchronous
|
||||||
|
// task in the background has finished. We set this variable to force
|
||||||
|
// an exit at the end of our code when `checkForTimeout` is called.
|
||||||
|
hadTimeout = true;
|
||||||
|
onTimeout();
|
||||||
|
}
|
||||||
resolve(undefined);
|
resolve(undefined);
|
||||||
}, timeoutMs);
|
}, timeoutMs);
|
||||||
});
|
});
|
||||||
|
|
@ -892,6 +908,22 @@ export async function withTimeout<T>(
|
||||||
return await Promise.race([mainTask(), timeout]);
|
return await Promise.race([mainTask(), timeout]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the global hadTimeout variable has been set, and if so then
|
||||||
|
* exit the process to ensure any background tasks that are still running
|
||||||
|
* are killed. This should be called at the end of execution if the
|
||||||
|
* `withTimeout` function has been used.
|
||||||
|
*/
|
||||||
|
export async function checkForTimeout() {
|
||||||
|
if (hadTimeout === true) {
|
||||||
|
core.info(
|
||||||
|
"A timeout occurred, force exiting the process after 30 seconds to prevent hanging."
|
||||||
|
);
|
||||||
|
await delay(30_000);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function implements a heuristic to determine whether the
|
* This function implements a heuristic to determine whether the
|
||||||
* runner we are on is hosted by GitHub. It does this by checking
|
* runner we are on is hosted by GitHub. It does this by checking
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue