diff options
-rw-r--r-- | doc/api/child_process.md | 15 | ||||
-rw-r--r-- | lib/internal/child_process.js | 7 | ||||
-rw-r--r-- | test/parallel/test-child-process-spawn-error.js | 2 | ||||
-rw-r--r-- | test/parallel/test-child-process-spawn-event.js | 27 |
4 files changed, 51 insertions, 0 deletions
diff --git a/doc/api/child_process.md b/doc/api/child_process.md index bfe7850ad0..0f78ba9d44 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1036,6 +1036,21 @@ child process, the `message` argument can contain data that JSON is not able to represent. See [Advanced serialization][] for more details. +### Event: `'spawn'` +<!-- YAML +added: REPLACEME +--> + +The `'spawn'` event is emitted once the child process has spawned successfully. + +If emitted, the `'spawn'` event comes before all other events and before any +data is received via `stdout` or `stderr`. + +The `'spawn'` event will fire regardless of whether an error occurs **within** +the spawned process. For example, if `bash some-command` spawns successfully, +the `'spawn'` event will fire, though `bash` may fail to spawn `some-command`. +This caveat also applies when using `{ shell: true }`. + ### `subprocess.channel` <!-- YAML added: v7.1.0 diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 092922f956..76e67317b9 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -401,6 +401,8 @@ ChildProcess.prototype.spawn = function(options) { this._handle.close(); this._handle = null; throw errnoException(err, 'spawn'); + } else { + process.nextTick(onSpawnNT, this); } this.pid = this._handle.pid; @@ -466,6 +468,11 @@ function onErrorNT(self, err) { } +function onSpawnNT(self) { + self.emit('spawn'); +} + + ChildProcess.prototype.kill = function(sig) { const signal = sig === 0 ? sig : diff --git a/test/parallel/test-child-process-spawn-error.js b/test/parallel/test-child-process-spawn-error.js index d6560ee9cc..a3464a505d 100644 --- a/test/parallel/test-child-process-spawn-error.js +++ b/test/parallel/test-child-process-spawn-error.js @@ -41,6 +41,8 @@ assert.strictEqual(enoentChild.stdio[0], enoentChild.stdin); assert.strictEqual(enoentChild.stdio[1], enoentChild.stdout); assert.strictEqual(enoentChild.stdio[2], enoentChild.stderr); +enoentChild.on('spawn', common.mustNotCall()); + enoentChild.on('error', common.mustCall(function(err) { assert.strictEqual(err.code, 'ENOENT'); assert.strictEqual(getSystemErrorName(err.errno), 'ENOENT'); diff --git a/test/parallel/test-child-process-spawn-event.js b/test/parallel/test-child-process-spawn-event.js new file mode 100644 index 0000000000..c025d86286 --- /dev/null +++ b/test/parallel/test-child-process-spawn-event.js @@ -0,0 +1,27 @@ +'use strict'; +const common = require('../common'); +const spawn = require('child_process').spawn; +const assert = require('assert'); + +const subprocess = spawn('echo', ['ok']); + +let didSpawn = false; +subprocess.on('spawn', function() { + didSpawn = true; +}); +function mustCallAfterSpawn() { + return common.mustCall(function() { + assert.ok(didSpawn); + }); +} + +subprocess.on('error', common.mustNotCall()); +subprocess.on('spawn', common.mustCall()); +subprocess.stdout.on('data', mustCallAfterSpawn()); +subprocess.stdout.on('end', mustCallAfterSpawn()); +subprocess.stdout.on('close', mustCallAfterSpawn()); +subprocess.stderr.on('data', common.mustNotCall()); +subprocess.stderr.on('end', mustCallAfterSpawn()); +subprocess.stderr.on('close', mustCallAfterSpawn()); +subprocess.on('exit', mustCallAfterSpawn()); +subprocess.on('close', mustCallAfterSpawn()); |