Skip to content

Commit 310c5db

Browse files
committed
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: #35288
1 parent af92317 commit 310c5db

File tree

4 files changed

+51
-0
lines changed

4 files changed

+51
-0
lines changed

doc/api/child_process.md

+15
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,21 @@ child process, the `message` argument can contain data that JSON is not able
10331033
to represent.
10341034
See [Advanced serialization][] for more details.
10351035

1036+
### Event: `'spawn'`
1037+
<!-- YAML
1038+
added: REPLACEME
1039+
-->
1040+
1041+
The `'spawn'` event is emitted once the child process has spawned successfully.
1042+
1043+
If emitted, the `'spawn'` event comes before all other events and before any
1044+
data is received via `stdout` or `stderr`.
1045+
1046+
The `'spawn'` event will fire regardless of whether an error occurs **within**
1047+
the spawned process. For example, if `bash some-command` spawns successfully,
1048+
the `'spawn'` event will fire, though `bash` may fail to spawn `some-command`.
1049+
This caveat also applies when using `{ shell: true }`.
1050+
10361051
### `subprocess.channel`
10371052
<!-- YAML
10381053
added: v7.1.0

lib/internal/child_process.js

+7
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ ChildProcess.prototype.spawn = function(options) {
400400
this._handle.close();
401401
this._handle = null;
402402
throw errnoException(err, 'spawn');
403+
} else {
404+
process.nextTick(onSpawnNT, this);
403405
}
404406

405407
this.pid = this._handle.pid;
@@ -465,6 +467,11 @@ function onErrorNT(self, err) {
465467
}
466468

467469

470+
function onSpawnNT(self) {
471+
self.emit('spawn');
472+
}
473+
474+
468475
ChildProcess.prototype.kill = function(sig) {
469476

470477
const signal = sig === 0 ? sig :

test/parallel/test-child-process-spawn-error.js

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ assert.strictEqual(enoentChild.stdio[0], enoentChild.stdin);
4141
assert.strictEqual(enoentChild.stdio[1], enoentChild.stdout);
4242
assert.strictEqual(enoentChild.stdio[2], enoentChild.stderr);
4343

44+
enoentChild.on('spawn', common.mustNotCall());
45+
4446
enoentChild.on('error', common.mustCall(function(err) {
4547
assert.strictEqual(err.code, 'ENOENT');
4648
assert.strictEqual(getSystemErrorName(err.errno), 'ENOENT');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
const common = require('../common');
3+
const spawn = require('child_process').spawn;
4+
const assert = require('assert');
5+
6+
const subprocess = spawn('echo', ['ok']);
7+
8+
let didSpawn = false;
9+
subprocess.on('spawn', function() {
10+
didSpawn = true;
11+
});
12+
function mustCallAfterSpawn() {
13+
return common.mustCall(function() {
14+
assert.ok(didSpawn);
15+
});
16+
}
17+
18+
subprocess.on('error', common.mustNotCall());
19+
subprocess.on('spawn', common.mustCall());
20+
subprocess.stdout.on('data', mustCallAfterSpawn());
21+
subprocess.stdout.on('end', mustCallAfterSpawn());
22+
subprocess.stdout.on('close', mustCallAfterSpawn());
23+
subprocess.stderr.on('data', common.mustNotCall());
24+
subprocess.stderr.on('end', mustCallAfterSpawn());
25+
subprocess.stderr.on('close', mustCallAfterSpawn());
26+
subprocess.on('exit', mustCallAfterSpawn());
27+
subprocess.on('close', mustCallAfterSpawn());

0 commit comments

Comments
 (0)