summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Francis Brunetti <zenflow87@gmail.com>2020-09-27 15:00:07 -0400
committerGireesh Punathil <gpunathi@in.ibm.com>2020-10-28 12:32:50 +0530
commit3df5afb367cf6ae4b6309ad54e1a9cb2e6884d27 (patch)
tree0a7f774b50476150044687800954bad4c903f83f
parent923f76d5231256e69985e1bd897fd490ea0cbe9c (diff)
downloadnode-new-3df5afb367cf6ae4b6309ad54e1a9cb2e6884d27.tar.gz
child_process: add ChildProcess 'spawn' event
The new event signals that the subprocess has spawned successfully and no 'error' event will be emitted from failing to spawn. Fixes: https://github.com/nodejs/node/issues/35288 PR-URL: https://github.com/nodejs/node/pull/35369 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
-rw-r--r--doc/api/child_process.md15
-rw-r--r--lib/internal/child_process.js7
-rw-r--r--test/parallel/test-child-process-spawn-error.js2
-rw-r--r--test/parallel/test-child-process-spawn-event.js27
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());