Closed
Description
- Version: v8.2.0 and newer
- Platform: Linux 4.2.0-27-generic docs: replace all instances of node.js with io.js because trademark. #32~14.04.1-Ubuntu x86_64 GNU/Linux
- Subsystem: child_process
Process started by child_process
module can start its own child process. For example tar
can start child process if we use it in concrete directory. And if we choose unexisting directory for archive destination it can fail in different way:
$ tar -C /some/directory -cvzf /path/to/archive.tgz fileToArchive
tar (child): /path/to/archive.tgz: Cannot open: No such file or directory
tar (child): Error is not recoverable: exiting now
example.js
$ echo $?
141
# and sometimes (1 from 10 or more runs) it can receive exit code 2 and finish correctly
$ tar -C /some/directory -cvzf /path/to/archive.tgz fileToArchive
fileToArchive
tar (child): /path/to/archive.tgz: Cannot open: No such file or directory
tar (child): Error is not recoverable: exiting now
tar: Child returned status 2
tar: Error is not recoverable: exiting now
$ echo $?
2
The problem here is that on NodeJS <8.2.0 it's always exit with code 2 because child process emit this exit code.
For example this script example.js
:
const spawn = require('child_process').spawn;
const Steppy = require('twostep').Steppy;
const pathUtils = require('path');
const assert = require('assert');
const exec = function(cmd, args) {
return new Promise((resolve, reject) => {
cmdSpawn = spawn(
cmd,
args,
{stdio: ['pipe', 'pipe', 'pipe']}
);
let stdoutData = '';
cmdSpawn.stdout.on('data', (data) => {
stdoutData += data;
});
let stderrData = '';
cmdSpawn.stderr.on('data', (data) => {
stderrData += data;
});
cmdSpawn.on('exit', (exitCode, signal) => {
console.log(exitCode, signal)
resolve({
stdoutData,
stderrData,
exitCode
});
});
cmdSpawn.on('error', (err) => {
promise.reject(new Error(err));
});
});
};
exec('tar', [
'-C',
__dirname,
'-cvzf',
pathUtils.join(__dirname, '/unexisted/path/archive.tgz'),
'example.js'
])
.then((result) => {
console.log(result);
assert.equal(result.exitCode, 2);
})
.catch((err) => {
console.error(err.stack || err);
});
will receive exit code 2 always on NodeJS 8.1.4 and this result on 8.2.0:
$ node example.js
null 'SIGPIPE'
{ stdoutData: 'example.js\n',
stderrData: 'tar (child): /home/robingood/work/gitlab/parking/price-calculator/scripts/unexisted/path/archive.tgz: Cannot open: No such file or directory\ntar (child): Error is not recoverable: exiting now\n',
exitCode: null }
AssertionError [ERR_ASSERTION]: null == 2
at exec.then (/home/robingood/work/gitlab/parking/price-calculator/scripts/example.js:50:10)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:189:7)
Why it happens? Is it correct behavior? What is right workaround for this case: handle signal in exit
listener?