I'm re-writing an existing module which spawns a child process and executes a command.
I've re-written it as a class but when I run the code, I get an error that the Promise rejects and resolve are undefined.
I assume that I pass them incorrectly to the .call
method but I did not find a different way I can pass them.
Here's the code:
import logger from './logger.utils';
import { spawn, ChildProcess } from 'child_process';
/**
* This function runs a spawn command and rejects the promise if timed out
* @param cmd - the command to execute
* @param params - the command's parameters
* @param timeoutMs - timeout in milliseconds
* @param taskDescription - a text description of the task for logging
*/
export class SpawnTimeout {
cmd: string;
params: string[];
finished: boolean;
childProcess: ChildProcess;
timeoutMs: number;
timeout: NodeJS.Timeout;
taskDescription: string;
handlers: Object;
constructor(
cmd: string,
params: string[],
timeoutMs: number,
taskDescription: string = 'no description specified'
) {
this.finished = false;
this.childProcess = spawn(cmd, params, {
stdio: [process.stdin, process.stdout, process.stderr],
});
this.timeoutMs = timeoutMs;
this.timeout = null;
this.taskDescription = taskDescription;
this.cmd = cmd;
this.params = params;
}
exec() {
return new Promise((resolve, reject) => {
const handlers = {
resolve,
reject,
};
this.handlers = handlers;
this.childProcess.once('error', this._onError.call(this.handlers));
this.childProcess.once('exit', this._onExit.call(this.handlers));
this.timeout = setTimeout(this._setTimeout, this.timeoutMs);
});
}
_onError(err: Error, handlers) {
clearTimeout(this.timeout);
const message = `spawn [${this.taskDescription}] ${this.cmd}, ${this.params} failed with error ${err}`;
logger.error(message);
handlers.reject(new Error(message));
}
_onExit(code: number, handlers) {
this.finished = true;
clearTimeout(this.timeout);
logger.debug(`spawn [${this.taskDescription}] finished.code ${code}`);
if (code == 0) {
handlers.resolve(true);
}
// case of error, code !== 0
const message = `spawn [${this.taskDescription}] cmd : ${this.cmd} ${this.params}. failed with code ${code}`;
logger.error(message);
handlers.reject(new Error(message));
}
_setTimeout() {
if (!this.finished) {
logger.warn(
`spawn [${this.taskDescription}] - timeout. cmd : ${this.cmd}, ${this.params}`
);
this.childProcess.kill();
}
}
}
The error is generated when handlers.resolve
or handlers.reject
are called.
Please advise how can I resolve this? or even if such an implementation good practice.
question from:
https://stackoverflow.com/questions/65936288/node-write-child-process-spawn-execution-in-class-form 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…