Skip to content

Commit ce2a801

Browse files
feat: allow setting timeout when using childProcess
In Node.js you can set timeout option to child processes started with `exec`. However, there's no support for this when using `spawn`. Add support for passing timeout in our abstraction of childProcess, when using `spawnFromEvent` method. When this method is used, it blocks the operation until the process finishes its execution. So it is appropriate to pass timeout and if it passes, send `SIGTERM` signal to the child process. This is the same signal used by Node.js when the timeout is hit in `child_process.exec`.
1 parent 6e366d8 commit ce2a801

File tree

2 files changed

+26
-6
lines changed

2 files changed

+26
-6
lines changed

lib/common/child-process.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,15 @@ export class ChildProcess extends EventEmitter implements IChildProcess {
6262
let isResolved = false;
6363
let capturedOut = "";
6464
let capturedErr = "";
65-
65+
let killTimer: NodeJS.Timer = null;
66+
67+
if (spawnFromEventOptions && spawnFromEventOptions.timeout) {
68+
this.$logger.trace(`Setting maximum time for execution of current child process to ${spawnFromEventOptions.timeout}`);
69+
killTimer = setTimeout(() => {
70+
this.$logger.trace(`Sending SIGTERM to current child process as maximum time for execution ${spawnFromEventOptions.timeout} had passed.`);
71+
childProcess.kill('SIGTERM');
72+
}, spawnFromEventOptions.timeout);
73+
}
6674
if (childProcess.stdout) {
6775
childProcess.stdout.on("data", (data: string) => {
6876
if (spawnFromEventOptions && spawnFromEventOptions.emitOptions && spawnFromEventOptions.emitOptions.eventName) {
@@ -91,17 +99,27 @@ export class ChildProcess extends EventEmitter implements IChildProcess {
9199
exitCode: exitCode
92100
};
93101

102+
const clearKillTimer = () => {
103+
if (killTimer) {
104+
clearTimeout(killTimer);
105+
}
106+
};
107+
108+
const resolveAction = () => {
109+
isResolved = true;
110+
resolve(result);
111+
clearKillTimer();
112+
};
113+
94114
if (spawnFromEventOptions && spawnFromEventOptions.throwError === false) {
95115
if (!isResolved) {
96116
this.$logger.trace("Result when throw error is false:");
97117
this.$logger.trace(result);
98-
isResolved = true;
99-
resolve(result);
118+
resolveAction();
100119
}
101120
} else {
102121
if (exitCode === 0) {
103-
isResolved = true;
104-
resolve(result);
122+
resolveAction();
105123
} else {
106124
let errorMessage = `Command ${command} failed with exit code ${exitCode}`;
107125
if (capturedErr) {
@@ -111,6 +129,7 @@ export class ChildProcess extends EventEmitter implements IChildProcess {
111129
if (!isResolved) {
112130
isResolved = true;
113131
reject(new Error(errorMessage));
132+
clearKillTimer();
114133
}
115134
}
116135
}

lib/common/declarations.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,8 @@ interface ISpawnFromEventOptions {
648648
throwError: boolean;
649649
emitOptions?: {
650650
eventName: string;
651-
}
651+
},
652+
timeout?: number;
652653
}
653654

654655
interface IProjectDir {

0 commit comments

Comments
 (0)