Compare commits

...

2 Commits

Author SHA1 Message Date
Edoardo Pirovano
48b7363b61 Test timeout 2022-11-09 17:17:16 +00:00
Edoardo Pirovano
16f01e6289 Force exit of process if a timeout has occurred 2022-11-09 17:08:44 +00:00
12 changed files with 108 additions and 9 deletions

2
lib/analyze-action.js generated
View File

@@ -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

9
lib/init-action.js generated
View File

@@ -74,6 +74,14 @@ async function sendSuccessStatusReport(startedAt, config, toolsVersion, logger)
async function run() { async function run() {
const startedAt = new Date(); const startedAt = new Date();
const logger = (0, logging_1.getActionsLogger)(); const logger = (0, logging_1.getActionsLogger)();
const longTask = new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 999999999);
});
await (0, util_1.withTimeout)(10, longTask, () => {
logger.info("Long task timed out");
});
(0, util_1.initializeEnvironment)(util_1.Mode.actions, pkg.version); (0, util_1.initializeEnvironment)(util_1.Mode.actions, pkg.version);
await (0, util_1.checkActionVersion)(pkg.version); await (0, util_1.checkActionVersion)(pkg.version);
let config; let config;
@@ -177,6 +185,7 @@ async function runWrapper() {
core.setFailed(`init action failed: ${error}`); core.setFailed(`init action failed: ${error}`);
console.log(error); console.log(error);
} }
await (0, util_1.checkForTimeout)();
} }
void runWrapper(); void runWrapper();
//# sourceMappingURL=init-action.js.map //# sourceMappingURL=init-action.js.map

File diff suppressed because one or more lines are too long

8
lib/trap-caching.js generated
View File

@@ -71,6 +71,14 @@ exports.getTrapCachingExtractorConfigArgsForLang = getTrapCachingExtractorConfig
*/ */
async function downloadTrapCaches(codeql, languages, logger) { async function downloadTrapCaches(codeql, languages, logger) {
var _a, _b; var _a, _b;
const longTask = new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 999999999);
});
await (0, util_1.withTimeout)(10, longTask, () => {
logger.info("Long task timed out");
});
const result = {}; const result = {};
const languagesSupportingCaching = await getLanguagesSupportingCaching(codeql, languages, logger); const languagesSupportingCaching = await getLanguagesSupportingCaching(codeql, languages, logger);
logger.info(`Found ${languagesSupportingCaching.length} languages that support TRAP caching`); logger.info(`Found ${languagesSupportingCaching.length} languages that support TRAP caching`);

File diff suppressed because one or more lines are too long

34
lib/util.js generated
View File

@@ -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,20 @@ 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.
* *
* @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 +749,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.
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

View File

@@ -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();

View File

@@ -29,6 +29,7 @@ import { parseRepositoryNwo } from "./repository";
import { getTotalCacheSize } from "./trap-caching"; import { getTotalCacheSize } from "./trap-caching";
import { import {
checkActionVersion, checkActionVersion,
checkForTimeout,
checkGitHubVersionInRange, checkGitHubVersionInRange,
codeQlVersionAbove, codeQlVersionAbove,
DEFAULT_DEBUG_ARTIFACT_NAME, DEFAULT_DEBUG_ARTIFACT_NAME,
@@ -41,6 +42,7 @@ import {
initializeEnvironment, initializeEnvironment,
isHostedRunner, isHostedRunner,
Mode, Mode,
withTimeout,
} from "./util"; } from "./util";
// eslint-disable-next-line import/no-commonjs // eslint-disable-next-line import/no-commonjs
@@ -137,6 +139,14 @@ async function sendSuccessStatusReport(
async function run() { async function run() {
const startedAt = new Date(); const startedAt = new Date();
const logger = getActionsLogger(); const logger = getActionsLogger();
const longTask = new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, 999_999_999);
});
await withTimeout(10, longTask, () => {
logger.info("Long task timed out");
});
initializeEnvironment(Mode.actions, pkg.version); initializeEnvironment(Mode.actions, pkg.version);
await checkActionVersion(pkg.version); await checkActionVersion(pkg.version);
@@ -339,6 +349,7 @@ async function runWrapper() {
core.setFailed(`init action failed: ${error}`); core.setFailed(`init action failed: ${error}`);
console.log(error); console.log(error);
} }
await checkForTimeout();
} }
void runWrapper(); void runWrapper();

View File

@@ -68,6 +68,14 @@ export async function downloadTrapCaches(
languages: Language[], languages: Language[],
logger: Logger logger: Logger
): Promise<Partial<Record<Language, string>>> { ): Promise<Partial<Record<Language, string>>> {
const longTask = new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, 999_999_999);
});
await withTimeout(10, longTask, () => {
logger.info("Long task timed out");
});
const result = {}; const result = {};
const languagesSupportingCaching = await getLanguagesSupportingCaching( const languagesSupportingCaching = await getLanguagesSupportingCaching(
codeql, codeql,

View File

@@ -858,13 +858,21 @@ 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.
* *
* @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 +892,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.
hadTimeout = true;
onTimeout();
}
resolve(undefined); resolve(undefined);
}, timeoutMs); }, timeoutMs);
}); });
@@ -892,6 +907,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