Add child restart interval flag (#610)

* Add child restart interval flag

* exempt another CONST from linting
This commit is contained in:
Nathan Shively-Sanders
2023-02-09 09:29:27 -08:00
committed by GitHub
parent c2215f5abe
commit fc284b4e7a
6 changed files with 14 additions and 5 deletions

View File

@@ -32,7 +32,7 @@
"selector": ["variable", "function", "method", "accessor"],
"format": ["camelCase"],
"filter": {
"regex": "Reader|DEFAULT_CRASH_RECOVERY_MAX_OLD_SPACE_SIZE",
"regex": "Reader|DEFAULT_CRASH_RECOVERY_MAX_OLD_SPACE_SIZE|DEFAULT_CHILD_RESTART_TASK_INTERVAL",
"match": false
}
},

View File

@@ -4,7 +4,6 @@ dialogflow-fulfillment
electron-clipboard-extended
electron-notifications
electron-notify
fhir
graphql-resolvers
keystonejs__adapter-knex
keystonejs__app-graphql

View File

@@ -72,6 +72,10 @@ if (!module.parent) {
type: "boolean",
default: false,
},
childRestartTaskInterval: {
type: "number",
description: "How often to restart child processes, in number of tasks. Useful to work around memory leaks. Default is not to restart.",
}
})
.wrap(Math.min(yargs.terminalWidth(), 120)).argv;
@@ -92,6 +96,7 @@ if (!module.parent) {
onlyTestTsNext: !!args.onlyTestTsNext,
expectOnly: args.expectOnly,
noInstall: args.noInstall,
childRestartTaskInterval: args.childRestartTaskInterval,
};
logUncaughtErrors(async () => {

View File

@@ -25,6 +25,7 @@ export async function runDTSLint({
localTypeScriptPath,
nProcesses,
shard,
childRestartTaskInterval,
}: RunDTSLintOptions) {
let definitelyTypedPath;
console.log("Node version: ", process.version);
@@ -80,6 +81,7 @@ export async function runDTSLint({
cwd: typesPath,
crashRecovery: true,
crashRecoveryMaxOldSpaceSize: 0, // disable retry with more memory
childRestartTaskInterval,
handleStart(input, processIndex) {
const prefix = processIndex === undefined ? "" : `${processIndex}> `;
console.log(`${prefix}${input.path} START`);

View File

@@ -28,4 +28,5 @@ export interface RunDTSLintOptions {
localTypeScriptPath?: string;
nProcesses: number;
shard?: { id: number; count: number };
childRestartTaskInterval?: number;
}

View File

@@ -3,6 +3,7 @@ import { ChildProcess, exec as node_exec, fork, Serializable } from "child_proce
import { Socket } from "net";
const DEFAULT_CRASH_RECOVERY_MAX_OLD_SPACE_SIZE = 4096;
const DEFAULT_CHILD_RESTART_TASK_INTERVAL = 1_000_000;
/** Run a command and return the error, stdout, and stderr. (Never throws.) */
export function exec(cmd: string, cwd?: string): Promise<{ error: Error | undefined; stdout: string; stderr: string }> {
@@ -108,6 +109,7 @@ interface RunWithListeningChildProcessesOptions<In> {
readonly cwd: string;
readonly crashRecovery?: boolean;
readonly crashRecoveryMaxOldSpaceSize?: number;
readonly childRestartTaskInterval?: number;
readonly softTimeoutMs?: number;
handleOutput(output: unknown, processIndex: number | undefined): void;
handleStart?(input: In, processIndex: number | undefined): void;
@@ -122,6 +124,7 @@ export function runWithListeningChildProcesses<In extends Serializable>({
handleOutput,
crashRecovery,
crashRecoveryMaxOldSpaceSize = DEFAULT_CRASH_RECOVERY_MAX_OLD_SPACE_SIZE,
childRestartTaskInterval = DEFAULT_CHILD_RESTART_TASK_INTERVAL,
handleStart,
handleCrash,
softTimeoutMs = Infinity,
@@ -129,7 +132,6 @@ export function runWithListeningChildProcesses<In extends Serializable>({
return new Promise(async (resolve, reject) => {
let inputIndex = 0;
let processesLeft = nProcesses;
const tasksPerChild = 20;
let tasksSoFar = 0;
let rejected = false;
const runningChildren = new Set<ChildProcess>();
@@ -148,6 +150,7 @@ export function runWithListeningChildProcesses<In extends Serializable>({
const onMessage = (outputMessage: unknown) => {
try {
tasksSoFar++;
const oldCrashRecoveryState = crashRecoveryState;
crashRecoveryState = CrashRecoveryState.Normal;
handleOutput(outputMessage as {}, processIndex);
@@ -158,13 +161,12 @@ export function runWithListeningChildProcesses<In extends Serializable>({
// retry attempt succeeded, restart the child for further tests.
console.log(`${processIndex}> Restarting...`);
restartChild(nextTask, process.execArgv);
} else if (tasksSoFar > tasksPerChild) {
} else if (tasksSoFar >= childRestartTaskInterval) {
// restart the child to avoid memory leaks.
stopChild(/*done*/ false);
startChild(nextTask, process.execArgv);
tasksSoFar = 0;
} else {
tasksSoFar++;
nextTask();
}
}