From c701d75d8c39cdb6ff702824e6bf445ff8cef4ee Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 21 Dec 2015 13:48:43 -0800 Subject: [PATCH] doc: improve child_process.markdown copy General improvements to child_process.markdown PR-URL: https://github.com/nodejs/node/pull/4383 Reviewed-By: Colin Ihrig --- doc/api/child_process.markdown | 974 ++++++++++++++++++++++++----------------- 1 file changed, 565 insertions(+), 409 deletions(-) diff --git a/doc/api/child_process.markdown b/doc/api/child_process.markdown index 1ab5322..029b63f 100644 --- a/doc/api/child_process.markdown +++ b/doc/api/child_process.markdown @@ -2,357 +2,113 @@ Stability: 2 - Stable -Node.js provides a tri-directional `popen(3)` facility through the -`child_process` module. - -It is possible to stream data through a child's `stdin`, `stdout`, and -`stderr` in a fully non-blocking way. (Note that some programs use -line-buffered I/O internally. That doesn't affect Node.js but it means -data you send to the child process may not be immediately consumed.) - -To create a child process, use `require('child_process').spawn()` or -`require('child_process').fork()`. The semantics of each are slightly -different as explained [below][]. - -For scripting purposes you may find the [synchronous counterparts][] more -convenient. - -## Class: ChildProcess - -`ChildProcess` is an [`EventEmitter`][]. - -Child processes always have three streams associated with them. `child.stdin`, -`child.stdout`, and `child.stderr`. These may be shared with the stdio -streams of the parent process, or they may be separate stream objects -which can be piped to and from. - -The `ChildProcess` class is not intended to be used directly. Use the -[`spawn()`][], [`exec()`][], [`execFile()`][], or [`fork()`][] methods to create -an instance of `ChildProcess`. - -### Event: 'close' - -* `code` {Number} the exit code, if it exited normally. -* `signal` {String} the signal passed to kill the child process, if it - was killed by the parent. - -This event is emitted when the stdio streams of a child process have all -terminated. This is distinct from `'exit'`, since multiple processes -might share the same stdio streams. - -### Event: 'disconnect' - -This event is emitted after calling the `.disconnect()` method in the parent -or in the child. After disconnecting it is no longer possible to send messages, -and the `.connected` property is false. - -### Event: 'error' - -* `err` {Error Object} the error. - -Emitted when: - -1. The process could not be spawned, or -2. The process could not be killed, or -3. Sending a message to the child process failed. - -Note that the `'exit'` event may or may not fire after an error has occurred. -If you are listening on both events to fire a function, remember to guard -against calling your function twice. - -See also [`ChildProcess#kill()`][] and [`ChildProcess#send()`][]. - -### Event: 'exit' - -* `code` {Number} the exit code, if it exited normally. -* `signal` {String} the signal passed to kill the child process, if it - was killed by the parent. - -This event is emitted after the child process ends. If the process terminated -normally, `code` is the final exit code of the process, otherwise `null`. If -the process terminated due to receipt of a signal, `signal` is the string name -of the signal, otherwise `null`. - -Note that the child process stdio streams might still be open. - -Also, note that Node.js establishes signal handlers for `SIGINT` and -`SIGTERM`. It will not terminate due to receipt of those signals. It will exit. - -See `waitpid(2)`. - -### Event: 'message' - -* `message` {Object} a parsed JSON object or primitive value. -* `sendHandle` {Handle object} a [`net.Socket`][] or [`net.Server`][] object, or - undefined. - -Messages sent by `.send(message, [sendHandle])` are obtained using the -`'message'` event. - -### child.connected - -* {Boolean} Set to false after `.disconnect` is called - -If `.connected` is false, it is no longer possible to send messages. - -### child.disconnect() - -Close the IPC channel between parent and child, allowing the child to exit -gracefully once there are no other connections keeping it alive. After calling -this method the `.connected` flag will be set to `false` in both the parent and -child, and it is no longer possible to send messages. - -The `'disconnect'` event will be emitted when there are no messages in the -process of being received, most likely immediately. - -Note that you can also call `process.disconnect()` in the child process when the -child process has any open IPC channels with the parent (i.e [`fork()`][]). - -### child.kill([signal]) - -* `signal` {String} - -Send a signal to the child process. If no argument is given, the process will -be sent `'SIGTERM'`. See `signal(7)` for a list of available signals. +The `child_process` module provides the ability to spawn child processes in +a manner that is similar, but not identical, to [`popen(3)`][]. This capability +is primarily provided by the `child_process.spawn()` function: const spawn = require('child_process').spawn; - const grep = spawn('grep', ['ssh']); + const ls = spawn('ls', ['-lh', '/usr']); - grep.on('close', (code, signal) => { - console.log( - `child process terminated due to receipt of signal ${signal}`); + ls.stdout.on('data', (data) => { + console.log(`stdout: ${data}`); }); - // send SIGHUP to process - grep.kill('SIGHUP'); - -May emit an `'error'` event when the signal cannot be delivered. Sending a -signal to a child process that has already exited is not an error but may -have unforeseen consequences. Specifically, if the process identifier (PID) has -been reassigned to another process, the signal will be delivered to that -process instead. What happens next is anyone's guess. - -Note that while the function is called `kill`, the signal delivered to the -child process may not actually kill it. `kill` really just sends a signal -to a process. - -See `kill(2)` - -### child.pid - -* {Integer} - -The process identifier (PID) of the child process. - -Example: - - const spawn = require('child_process').spawn; - const grep = spawn('grep', ['ssh']); - - console.log(`Spawned child pid: ${grep.pid}`); - grep.stdin.end(); - -### child.send(message[, sendHandle][, callback]) - -* `message` {Object} -* `sendHandle` {Handle object} -* `callback` {Function} -* Return: Boolean - -When using [`child_process.fork()`][] you can write to the child using -`child.send(message[, sendHandle][, callback])` and messages are received by -a `'message'` event on the child. - -For example: - - const cp = require('child_process'); - const n = cp.fork(`${__dirname}/sub.js`); - - n.on('message', (m) => { - console.log('PARENT got message:', m); + ls.stderr.on('data', (data) => { + console.log(`stderr: ${data}`); }); - n.send({ hello: 'world' }); - -And then the child script, `'sub.js'` might look like this: - - process.on('message', (m) => { - console.log('CHILD got message:', m); + ls.on('close', (code) => { + console.log(`child process exited with code ${code}`); }); - process.send({ foo: 'bar' }); - -In the child, the `process` object will have a `send()` method, and `process` -will emit objects each time it receives a message on its channel. +By default, pipes for `stdin`, `stdout` and `stderr` are established between +the parent Node.js process and the spawned child. It is possible to stream data +through these pipes in a non-blocking way. *Note, however, that some programs +use line-buffered I/O internally. While that does not affect Node.js, it can +mean that data sent to the child process may not be immediately consumed.* + +The `child_process.spawn()` method spawns the child process asynchronously, +without blocking the Node.js event loop. The `child_process.spawnSync()` +function provides equivalent functionality in a synchronous manner that blocks +the event loop until the spawned process either exits of is terminated. + +For convenience, the `child_process` module provides a handful of synchronous +and asynchronous alternatives to `child_process.spawn()` and +`child_process.spawnSync()`, each of which are documented fully [below][]. +*Note that each of these alternatives are implemented on top of +`child_process.spawn()` or `child_process.spawnSync()`.* + + * `child_process.exec()`: spawns a shell and runs a command within that shell, + passing the `stdout` and `stderr` to a callback function when complete. + * `child_process.execFile()`: similar to `child_process.exec()` except that + it spawns the command directly without first spawning a shell. + * `child_process.fork()`: spawns a new Node.js process and invokes a + specified module with an IPC communication channel established that allows + sending messages between parent and child. + * `child_process.execSync()`: a synchronous version of + `child_process.exec()` that *will* block the Node.js event loop. + * `child_process.execFileSync()`: a synchronous version of + `child_process.execFile()` that *will* block the Node.js event loop. + +For certain use cases, such as automating shell scripts, the +[synchronous counterparts][] may be more convenient. In many cases, however, +the synchronous methods can have significant impact on performance due to +stalling the event loop while spawned processes complete. -There is a special case when sending a `{cmd: 'NODE_foo'}` message. All messages -containing a `NODE_` prefix in its `cmd` property will not be emitted in -the `'message'` event, since they are internal messages used by Node.js core. -Messages containing the prefix are emitted in the `'internalMessage'` event. -Avoid using this feature; it is subject to change without notice. - -The `sendHandle` option to `child.send()` is for sending a TCP server or -socket object to another process. The child will receive the object as its -second argument to the `'message'` event. +## Asynchronous Process Creation -The `callback` option is a function that is invoked after the message is -sent but before the target may have received it. It is called with a single -argument: `null` on success, or an [`Error`][] object on failure. +The `child_process.spawn()`, `child_process.fork()`, `child_process.exec()`, +and `child_process.execFile()` methods all follow the idiomatic asynchronous +programming pattern typical of other Node.js APIs. -`child.send()` emits an `'error'` event if no callback was given and the message -cannot be sent, for example because the child process has already exited. +Each of the methods returns a [ChildProcess][] instance. These objects +implement the Node.js [EventEmitter][] API, allowing the parent process to +register listener functions that are called when certain events occur during +the life cycle of the child process. -Returns `true` under normal circumstances or `false` when the backlog of -unsent messages exceeds a threshold that makes it unwise to send more. -Use the callback mechanism to implement flow control. +The `child_process.exec()` and `child_process.execFile()` methods additionally +allow for an optional `callback` function to be specified that is invoked +when the child process terminates. -#### Example: sending server object +### Spawning `.bat` and `.cmd` files on Windows -Here is an example of sending a server: +The importance of the distinction between `child_process.exec()` and +`child_process.execFile()` can vary based on platform. On Unix-type operating +systems (Unix, Linux, OSX) `child_process.execFile()` can be more efficient +because it does not spawn a shell. On Windows, however, `.bat` and `.cmd` +files are not executable on their own without a terminal and therefore cannot +be launched using `child_process.execFile()` (or even `child_process.spawn()`). +When running on Windows, `.bat` and `.cmd` files can only be invoked using +either `child_process.exec()` or by spawning `cmd.exe` and passing the `.bat` +or `.cmd` file as an argument (which is what `child_process.exec()` does). - const child = require('child_process').fork('child.js'); + // On Windows Only ... + const spawn = require('child_process').spawn; + const bat = spawn('cmd.exe', ['/c', 'my.bat']); - // Open up the server object and send the handle. - const server = require('net').createServer(); - server.on('connection', (socket) => { - socket.end('handled by parent'); - }); - server.listen(1337, () => { - child.send('server', server); + bat.stdout.on('data', (data) => { + console.log(data); }); -And the child would then receive the server object as: - - process.on('message', (m, server) => { - if (m === 'server') { - server.on('connection', (socket) => { - socket.end('handled by child'); - }); - } + bat.stderr.on('data', (data) => { + console.log(data); }); -Note that the server is now shared between the parent and child, this means -that some connections will be handled by the parent and some by the child. - -For `dgram` servers the workflow is exactly the same. Here you listen on -a `'message'` event instead of `'connection'` and use `server.bind` instead of -`server.listen`. (Currently only supported on UNIX platforms.) - -#### Example: sending socket object - -Here is an example of sending a socket. It will spawn two children and handle -connections with the remote address `74.125.127.100` as VIP by sending the -socket to a "special" child process. Other sockets will go to a "normal" -process. - - const normal = require('child_process').fork('child.js', ['normal']); - const special = require('child_process').fork('child.js', ['special']); - - // Open up the server and send sockets to child - const server = require('net').createServer(); - server.on('connection', (socket) => { - - // if this is a VIP - if (socket.remoteAddress === '74.125.127.100') { - special.send('socket', socket); - return; - } - // just the usual... - normal.send('socket', socket); + bat.on('exit', (code) => { + console.log(`Child exited with code ${code}`); }); - server.listen(1337); - -The `child.js` could look like this: - process.on('message', (m, socket) => { - if (m === 'socket') { - socket.end(`You were handled as a ${process.argv[2]} person`); + // OR... + const exec = require('child_process').exec; + exec('my.bat', (err, stdout, stderr) => { + if (err) { + console.error(err); + return; } + console.log(stdout); }); -Note that once a single socket has been sent to a child the parent can no -longer keep track of when the socket is destroyed. To indicate this condition -the `.connections` property becomes `null`. -It is also recommended not to use `.maxConnections` in this condition. - -### child.stderr - -* {Stream object} - -A `Readable Stream` that represents the child process's `stderr`. - -If the child was not spawned with `stdio[2]` set to `'pipe'`, then this will -not be set. - -`child.stderr` is shorthand for `child.stdio[2]`. Both properties will refer -to the same object, or null. - -### child.stdin - -* {Stream object} - -A `Writable Stream` that represents the child process's `stdin`. -If the child is waiting to read all its input, it will not continue until this -stream has been closed via `end()`. - -If the child was not spawned with `stdio[0]` set to `'pipe'`, then this will -not be set. - -`child.stdin` is shorthand for `child.stdio[0]`. Both properties will refer -to the same object, or null. - -### child.stdio - -* {Array} - -A sparse array of pipes to the child process, corresponding with positions in -the [`stdio`][] option to [`spawn()`][] that have been set to `'pipe'`. -Note that streams 0-2 are also available as ChildProcess.stdin, -ChildProcess.stdout, and ChildProcess.stderr, respectively. - -In the following example, only the child's fd `1` is setup as a pipe, so only -the parent's `child.stdio[1]` is a stream, all other values in the array are -`null`. - - const assert = require('assert'); - const fs = require('fs'); - const child_process = require('child_process'); - - const child = child_process.spawn('ls', { - stdio: [ - 0, // use parents stdin for child - 'pipe', // pipe child's stdout to parent - fs.openSync('err.out', 'w') // direct child's stderr to a file - ] - }); - - assert.equal(child.stdio[0], null); - assert.equal(child.stdio[0], child.stdin); - - assert(child.stdout); - assert.equal(child.stdio[1], child.stdout); - - assert.equal(child.stdio[2], null); - assert.equal(child.stdio[2], child.stderr); - -### child.stdout - -* {Stream object} - -A `Readable Stream` that represents the child process's `stdout`. - -If the child was not spawned with `stdio[1]` set to `'pipe'`, then this will -not be set. - -`child.stdout` is shorthand for `child.stdio[1]`. Both properties will refer -to the same object, or null. - -## Asynchronous Process Creation - -These methods follow the common async programming patterns (accepting a -callback or returning an EventEmitter). - -### child_process.exec(command[, options], callback) +### child_process.exec(command[, options][, callback]) * `command` {String} The command to run, with space-separated arguments * `options` {Object} @@ -375,7 +131,8 @@ callback or returning an EventEmitter). * `stderr` {Buffer} * Return: ChildProcess object -Runs a command in a shell and buffers the output. +Spawns a shell then executes the `command` within that shell, buffering any +generated output. const exec = require('child_process').exec; const child = exec('cat *.js bad_file | wc -l', @@ -387,29 +144,35 @@ Runs a command in a shell and buffers the output. } }); -The callback gets the arguments `(error, stdout, stderr)`. On success, `error` -will be `null`. On error, `error` will be an instance of [`Error`][] and `error.code` -will be the exit code of the child process, and `error.signal` will be set to the -signal that terminated the process. +If a `callback` function is provided, it is called with the arguments +`(error, stdout, stderr)`. On success, `error` will be `null`. On error, +`error` will be an instance of [`Error`][]. The `error.code` property will be +the exit code of the child process while `error.signal` will be set to the +signal that terminated the process. Any exit code other than `0` is considered +to be an error. -There is a second optional argument to specify several options. The -default options are +The `options` argument may be passed as the second argument to customize how +the process is spawned. The default options are: - { encoding: 'utf8', + { + encoding: 'utf8', timeout: 0, maxBuffer: 200*1024, killSignal: 'SIGTERM', cwd: null, - env: null } + env: null + } -If `timeout` is greater than 0, then it will kill the child process -if it runs longer than `timeout` milliseconds. The child process is killed with -`killSignal` (default: `'SIGTERM'`). `maxBuffer` specifies the largest -amount of data (in bytes) allowed on stdout or stderr - if this value is -exceeded then the child process is killed. +If `timeout` is greater than `0`, the parent will send the the signal +identified by the `killSignal` property (the default is `'SIGTERM'`) if the +child runs longer than `timeout` milliseconds. -*Note: Unlike the `exec()` POSIX system call, `child_process.exec()` does not replace -the existing process and uses a shell to execute the command.* +The `maxBuffer` option specifies the largest amount of data (in bytes) allowed +on stdout or stderr - if this value is exceeded then the child process is +terminated. + +*Note: Unlike the `exec()` POSIX system call, `child_process.exec()` does not +replace the existing process and uses a shell to execute the command.* ### child_process.execFile(file[, args][, options][, callback]) @@ -431,10 +194,21 @@ the existing process and uses a shell to execute the command.* * `stderr` {Buffer} * Return: ChildProcess object -This is similar to [`child_process.exec()`][] except it does not execute a -subshell but rather the specified file directly. This makes it slightly -leaner than [`child_process.exec()`][]. It has the same options. +The `child_process.execFile()` method is similar to [`child_process.exec()`][] +except that it does not first spawn a shell. Rather, the specified `command` is +spawned directly as a new process making it slightly more efficient than +[`child_process.exec()`][]. The same options are support by both +`child_process.exec()` and `child_process.execFile()`. + const exec = require('child_process').execFile; + const child = execFile('cat *.js bad_file | wc -l', + (error, stdout, stderr) => { + console.log(`stdout: ${stdout}`); + console.log(`stderr: ${stderr}`); + if (error !== null) { + console.log(`exec error: ${error}`); + } + }); ### child_process.fork(modulePath[, args][, options]) @@ -454,23 +228,31 @@ leaner than [`child_process.exec()`][]. It has the same options. * `gid` {Number} Sets the group identity of the process. (See setgid(2).) * Return: ChildProcess object -This is a special case of the [`child_process.spawn()`][] functionality for -spawning Node.js processes. In addition to having all the methods in a normal -ChildProcess instance, the returned object has a communication channel built-in. -See [`ChildProcess#send()`][] for details. - -These child Node.js processes are still whole new instances of V8. Assume at -least 30ms startup and 10mb memory for each new Node.js. That is, you cannot -create many thousands of them. - -The `execPath` property in the `options` object allows for a process to be -created for the child rather than the current `node` executable. This should be -done with care and by default will talk over the fd represented an -environmental variable `NODE_CHANNEL_FD` on the child process. The input and +The `child_process.fork()` method is a special case of +[`child_process.spawn()`][] used specifically to spawn new Node.js processes. +Like `child_process.spawn()`, a `ChildProcess` object is returned. The returned +`ChildProcess` will have an additional communication channel built-in that +allows messages to be passed back and forth between the parent and child. See +[`ChildProcess#send()`][] for details. + +It is important to keep in mind that spawned Node.js child processes are +independent of the parent with exception of the IPC communication channel +that is established between the two. Each process has it's own memory, with +their own V8 instances. Because of the additional resource allocations +required, spawning a large number of child Node.js processes is not +recommended. + +By default, `child_process.fork()` will spawn new Node.js instances using the +`process.execPath` of the parent process. The `execPath` property in the +`options` object allows for an alternative execution path to be used. + +Node.js processes launched with a custom `execPath` will communicate with the +parent process using the file descriptor (fd) identified using the +environment variable `NODE_CHANNEL_FD` on the child process. The input and output on this fd is expected to be line delimited JSON objects. -*Note: Unlike the `fork()` POSIX system call, [`child_process.fork()`][] does not clone the -current process.* +*Note: Unlike the `fork()` POSIX system call, [`child_process.fork()`][] does +not clone the current process.* ### child_process.spawn(command[, args][, options]) @@ -488,12 +270,14 @@ current process.* * `gid` {Number} Sets the group identity of the process. (See setgid(2).) * return: {ChildProcess object} -Launches a new process with the given `command`, with command line arguments in -`args`. If omitted, `args` defaults to an empty Array. +The `child_process.spawn()` method spawns a new process using the given +`command`, with command line arguments in `args`. If omitted, `args` defaults +to an empty array. -The third argument is used to specify additional options, with these defaults: +A third argument may be used to specify additional options, with these defaults: - { cwd: undefined, + { + cwd: undefined, env: process.env } @@ -503,7 +287,8 @@ If not given, the default is to inherit the current working directory. Use `env` to specify environment variables that will be visible to the new process, the default is `process.env`. -Example of running `ls -lh /usr`, capturing `stdout`, `stderr`, and the exit code: +Example of running `ls -lh /usr`, capturing `stdout`, `stderr`, and the +exit code: const spawn = require('child_process').spawn; const ls = spawn('ls', ['-lh', '/usr']); @@ -568,18 +353,21 @@ Example of checking for failed exec: #### options.detached -On Windows, this makes it possible for the child to continue running after the -parent exits. The child will have a new console window (this cannot be -disabled). +On Windows, setting `options.detached` to `true` makes it possible for the +child process to continue running after the parent exits. The child will have +its own console window. *Once enabled for a child process, it cannot be +disabled*. -On non-Windows, if the `detached` option is set, the child process will be made -the leader of a new process group and session. Note that child processes may -continue running after the parent exits whether they are detached or not. See -`setsid(2)` for more information. +On non-Windows platforms, if `options.detached` is set to `true`, the child +process will be made the leader of a new process group and session. Note that +child processes may continue running after the parent exits regardless of +whether they are detached or not. See `setsid(2)` for more information. -By default, the parent will wait for the detached child to exit. To prevent -the parent from waiting for a given `child`, use the `child.unref()` method, -and the parent's event loop will not include the child in its reference count. +By default, the parent will wait for the detached child to exit. To prevent +the parent from waiting for a given `child`, use the `child.unref()` method. +Doing so will cause the parent's event loop to not include the child in its +reference count, allowing the parent to exit independently of the child, unless +there is an established IPC channel between the child and parent. Example of detaching a long-running process and redirecting its output to a file: @@ -604,14 +392,23 @@ controlling terminal. #### options.stdio -As a shorthand, the `stdio` argument may be one of the following strings: +The `options.stdio` option is used to configure the pipes that are established +between the parent and child process. By default, the child's stdin, stdout, +and stderr are redirected to corresponding `child.stdin`, `child.stdout`, and +`child.stderr` streams on the `ChildProcess` object. This is equivalent to +setting the `options.stdio` equal to `['pipe', 'pipe', 'pipe']`. + +For convenience, `options.stdio` may be one of the following strings: -* `'pipe'` - `['pipe', 'pipe', 'pipe']`, this is the default value -* `'ignore'` - `['ignore', 'ignore', 'ignore']` -* `'inherit'` - `[process.stdin, process.stdout, process.stderr]` or `[0,1,2]` +* `'pipe'` - equivalent to `['pipe', 'pipe', 'pipe']` (the default) +* `'ignore'` - equivalent to `['ignore', 'ignore', 'ignore']` +* `'inherit'` - equivalent to `[process.stdin, process.stdout, process.stderr]` + or `[0,1,2]` -Otherwise, the `'stdio'` option to [`child_process.spawn()`][] is an array where each -index corresponds to a fd in the child. The value is one of the following: +Otherwise, the value of `option.stdio` is an array where each index corresponds +to an fd in the child. The fds 0, 1, and 2 correspond to stdin, stdout, +and stderr, respectively. Additional fds can be specified to create additional +pipes between the parent and child. The value is one of the following: 1. `'pipe'` - Create a pipe between the child process and the parent process. The parent end of the pipe is exposed to the parent as a property on the @@ -621,13 +418,15 @@ index corresponds to a fd in the child. The value is one of the following: 2. `'ipc'` - Create an IPC channel for passing messages/file descriptors between parent and child. A ChildProcess may have at most *one* IPC stdio file descriptor. Setting this option enables the ChildProcess.send() method. - If the child writes JSON messages to this file descriptor, then this will - trigger ChildProcess.on('message'). If the child is an Node.js program, then - the presence of an IPC channel will enable process.send() and - process.on('message'). -3. `'ignore'` - Do not set this file descriptor in the child. Note that Node.js - will always open fd 0 - 2 for the processes it spawns. When any of these is - ignored Node.js will open `/dev/null` and attach it to the child's fd. + If the child writes JSON messages to this file descriptor, the + `ChildProcess.on('message')` event handler will be triggered in the parent. + If the child is a Node.js process, the presence of an IPC channel will enable + `process.send()`, `process.disconnect()`, `process.on('disconnect')`, and + `process.on('message')` within the child. +3. `'ignore'` - Instructs Node.js to ignore the fd in the child. While Node.js + will always open fds 0 - 2 for the processes it spawns, setting the fd to + `'ignore'` will cause Node.js to open `/dev/null` and attach it to the + child's fd. 4. `Stream` object - Share a readable or writable stream that refers to a tty, file, socket, or a pipe with the child process. The stream's underlying file descriptor is duplicated in the child process to the fd that @@ -651,16 +450,25 @@ Example: // Spawn child sharing only stderr spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] }); - // Open an extra fd=4, to interact with programs present a + // Open an extra fd=4, to interact with programs presenting a // startd-style interface. spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] }); +*It is worth noting that when an IPC channel is established between the +parent and child processes, and the child is a Node.js process, the child +is launched with the IPC channel unreferenced (using `unref()`) until the +child registers an event handler for the `process.on('disconnected')` event. +This allows the child to exit normally without the process being held open +by the open IPC channel.* + See also: [`child_process.exec()`][] and [`child_process.fork()`][] ## Synchronous Process Creation -These methods are **synchronous**, meaning they **WILL** block the event loop, -pausing execution of your code until the spawned process exits. +The `child_process.spawnSync()`, `child_process.execSync()`, and +`child_process.execFileSync()` methods are **synchronous** and **WILL** block +the Node.js event loop, pausing execution of any additional code until the +spawned process exits. Blocking calls like these are mostly useful for simplifying general purpose scripting tasks and for simplifying the loading/processing of application @@ -687,11 +495,13 @@ configuration at startup. * `encoding` {String} The encoding used for all stdio inputs and outputs. (Default: 'buffer') * return: {Buffer|String} The stdout from the command -`execFileSync` will not return until the child process has fully closed. When a -timeout has been encountered and `killSignal` is sent, the method won't return -until the process has completely exited. That is to say, if the process handles -the `SIGTERM` signal and doesn't exit, your process will wait until the child -process has exited. +The `child_process.execFileSync()` method is generally identical to +`child_process.execFile()` with the exception that the method will not return +until the child process has fully closed. When a timeout has been encountered +and `killSignal` is sent, the method won't return until the process has +completely exited. *Note that if the child process intercepts and handles +the `SIGTERM` signal and does not exit, the parent process will still wait +until the child process has exited.* If the process times out, or has a non-zero exit code, this method ***will*** throw. The [`Error`][] object will contain the entire result from @@ -721,11 +531,13 @@ throw. The [`Error`][] object will contain the entire result from * `encoding` {String} The encoding used for all stdio inputs and outputs. (Default: 'buffer') * return: {Buffer|String} The stdout from the command -`execSync` will not return until the child process has fully closed. When a -timeout has been encountered and `killSignal` is sent, the method won't return -until the process has completely exited. That is to say, if the process handles -the `SIGTERM` signal and doesn't exit, your process will wait until the child -process has exited. +The `child_process.execSync()` method is generally identical to +`child_process.exec()` with the exception that the method will not return until +the child process has fully closed. When a timeout has been encountered and +`killSignal` is sent, the method won't return until the process has completely +exited. *Note that if the child process intercepts and handles the `SIGTERM` +signal and doesn't exit, the parent process will wait until the child +process has exited.* If the process times out, or has a non-zero exit code, this method ***will*** throw. The [`Error`][] object will contain the entire result from @@ -757,26 +569,370 @@ throw. The [`Error`][] object will contain the entire result from * `signal` {String} The signal used to kill the child process * `error` {Error} The error object if the child process failed or timed out -`spawnSync` will not return until the child process has fully closed. When a -timeout has been encountered and `killSignal` is sent, the method won't return -until the process has completely exited. That is to say, if the process handles -the `SIGTERM` signal and doesn't exit, your process will wait until the child +The `child_process.spawnSync()` method is generally identical to +`child_process.spawn()` with the exception that the function will not return +until the child process has fully closed. When a timeout has been encountered +and `killSignal` is sent, the method won't return until the process has +completely exited. Note that if the process intercepts and handles the +`SIGTERM` signal and doesn't exit, the parent process will wait until the child process has exited. +## Class: ChildProcess + +Instances of the `ChildProcess` class are [`EventEmitters`][] that represent +spawned child processes. + +Instances of `ChildProcess` are not intended to be created directly. Rather, +use the [`child_process.spawn()`][], [`child_process.exec()`][], +[`child_process.execFile()`][], or [`child_process.fork()`][] methods to create +instances of `ChildProcess`. + +### Event: 'close' + +* `code` {Number} the exit code if the child exited on its own. +* `signal` {String} the signal by which the child process was terminated. + +The `'close'` event is emitted when the stdio streams of a child process have +been closed. This is distinct from the `'exit'` event, since multiple +processes might share the same stdio streams. + +### Event: 'disconnect' + +The `'disconnect'` event is emitted after calling the +`ChildProcess.disconnect()` method in the parent or child process. After +disconnecting it is no longer possible to send or receive messages, and the +`ChildProcess.connected` property is false. + +### Event: 'error' + +* `err` {Error Object} the error. + +The `'error'` event is emitted whenever: + +1. The process could not be spawned, or +2. The process could not be killed, or +3. Sending a message to the child process failed. + +Note that the `'exit'` event may or may not fire after an error has occurred. +If you are listening to both the `'exit'` and `'error'` events, it is important +to guard against accidentally invoking handler functions multiple times. + +See also [`ChildProcess#kill()`][] and [`ChildProcess#send()`][]. + +### Event: 'exit' + +* `code` {Number} the exit code if the child exited on its own. +* `signal` {String} the signal by which the child process was terminated. + +The `'exit'` event is emitted after the child process ends. If the process +exited, `code` is the final exit code of the process, otherwise `null`. If the +process terminated due to receipt of a signal, `signal` is the string name of +the signal, otherwise `null`. One of the two will always be non-null. + +Note that when the `'exit'` event is triggered, child process stdio streams +might still be open. + +Also, note that Node.js establishes signal handlers for `SIGINT` and +`SIGTERM` and Node.js processes will not terminate immediately due to receipt +of those signals. Rather, Node.js will perform a sequence of cleanup actions +and then will re-raise the handled signal. + +See `waitpid(2)`. + +### Event: 'message' + +* `message` {Object} a parsed JSON object or primitive value. +* `sendHandle` {Handle object} a [`net.Socket`][] or [`net.Server`][] object, or + undefined. + +The `'message'` event is triggered when a child process uses `process.send()` +to send messages. + +### child.connected + +* {Boolean} Set to false after `.disconnect` is called + +The `child.connected` property indicates whether it is still possible to send +and receive messages from a child process. When `child.connected` is false, it +is no longer possible to send or receive messages. + +### child.disconnect() + +Closes the IPC channel between parent and child, allowing the child to exit +gracefully once there are no other connections keeping it alive. After calling +this method the `child.connected` and `process.connected` properties in both +the parent and child (respectively) will be set to `false`, and it will be no +longer possible to pass messages between the processes. + +The `'disconnect'` event will be emitted when there are no messages in the +process of being received. This will most often be triggered immediately after +calling `child.disconnect()`. + +Note that when the child process is a Node.js instance (e.g. spawned using +[`child_process.fork()`]), the `process.disconnect()` method can be invoked +within the child process to close the IPC channel as well. + +### child.kill([signal]) + +* `signal` {String} + +The `child.kill()` methods sends a signal to the child process. If no argument +is given, the process will be sent the `'SIGTERM'` signal. See `signal(7)` for +a list of available signals. + + const spawn = require('child_process').spawn; + const grep = spawn('grep', ['ssh']); + + grep.on('close', (code, signal) => { + console.log( + `child process terminated due to receipt of signal ${signal}`); + }); + + // Send SIGHUP to process + grep.kill('SIGHUP'); + +The `ChildProcess` object may emit an `'error'` event if the signal cannot be +delivered. Sending a signal to a child process that has already exited is not +an error but may have unforeseen consequences. Specifically, if the process +identifier (PID) has been reassigned to another process, the signal will be +delivered to that process instead which can have unexpected results. + +Note that while the function is called `kill`, the signal delivered to the +child process may not actually terminate the process. + +See `kill(2)` + +### child.pid + +* {Integer} + +Returns the process identifier (PID) of the child process. + +Example: + + const spawn = require('child_process').spawn; + const grep = spawn('grep', ['ssh']); + + console.log(`Spawned child pid: ${grep.pid}`); + grep.stdin.end(); + +### child.send(message[, sendHandle][, callback]) + +* `message` {Object} +* `sendHandle` {Handle object} +* `callback` {Function} +* Return: Boolean + +When an IPC channel has been established between the parent and child ( +i.e. when using [`child_process.fork()`][]), the `child.send()` method can be +used to send messages to the child process. When the child process is a Node.js +instance, these messages can be received via the `process.on('message')` event. + +For example, in the parent script: + + const cp = require('child_process'); + const n = cp.fork(`${__dirname}/sub.js`); + + n.on('message', (m) => { + console.log('PARENT got message:', m); + }); + + n.send({ hello: 'world' }); + +And then the child script, `'sub.js'` might look like this: + + process.on('message', (m) => { + console.log('CHILD got message:', m); + }); + + process.send({ foo: 'bar' }); + +Child Node.js processes will have a `process.send()` method of their own that +allows the child to send messages back to the parent. + +There is a special case when sending a `{cmd: 'NODE_foo'}` message. All messages +containing a `NODE_` prefix in its `cmd` property are considered to be reserved +for use within Node.js core and will not be emitted in the child's +`process.on('message')` event. Rather, such messages are emitted using the +`process.on('internalMessage')` event and are consumed internally by Node.js. +Applications should avoid using such messages or listening for +`'internalMessage'` events as it is subject to change without notice. + +The optional `sendHandle` argument that may be passed to `child.send()` is for +passing a TCP server or socket object to the child process. The child will +receive the object as the second argument passed to the callback function +registered on the `process.on('message')` event. + +The optional `callback` is a function that is invoked after the message is +sent but before the child may have received it. The function is called with a +single argument: `null` on success, or an [`Error`][] object on failure. + +If no `callback` function is provided and the message cannot be sent, an +`'error'` event will be emitted by the `ChildProcess` object. This can happen, +for instance, when the child process has already exited. + +`child.send()` will return `false` if the channel has closed or when the +backlog of unsent messages exceeds a threshold that makes it unwise to send +more. Otherwise, the method returns `true`. The `callback` function can be +used to implement flow control. + +#### Example: sending a server object + +The `sendHandle` argument can be used, for instance, to pass the handle of +a TSCP server object to the child process as illustrated in the example below: + + const child = require('child_process').fork('child.js'); + + // Open up the server object and send the handle. + const server = require('net').createServer(); + server.on('connection', (socket) => { + socket.end('handled by parent'); + }); + server.listen(1337, () => { + child.send('server', server); + }); + +The child would then receive the server object as: + + process.on('message', (m, server) => { + if (m === 'server') { + server.on('connection', (socket) => { + socket.end('handled by child'); + }); + } + }); + +Once the server is now shared between the parent and child, some connections +can be handled by the parent and some by the child. + +While the example above uses a server created using the `net` module, `dgram` +module servers use exactly the same workflow with the exceptions of listening on +a `'message'` event instead of `'connection'` and using `server.bind` instead of +`server.listen`. This is, however, currently only supported on UNIX platforms. + +#### Example: sending a socket object + +Similarly, the `sendHandler` argument can be used to pass the handle of a +socket to the child process. The example below spawns two children that each +handle connections with "normal" or "special" priority: + + const normal = require('child_process').fork('child.js', ['normal']); + const special = require('child_process').fork('child.js', ['special']); + + // Open up the server and send sockets to child + const server = require('net').createServer(); + server.on('connection', (socket) => { + + // If this is special priority + if (socket.remoteAddress === '74.125.127.100') { + special.send('socket', socket); + return; + } + // This is normal priority + normal.send('socket', socket); + }); + server.listen(1337); + +The `child.js` would receive the socket handle as the second argument passed +to the event callback function: + + process.on('message', (m, socket) => { + if (m === 'socket') { + socket.end(`Request handled with ${process.argv[2]} priority`); + } + }); + +Once a socket has been passed to a child, the parent is no longer capable of +tracking when the socket is destroyed. To indicate this, the `.connections` +property becomes `null`. It is recommended not to use `.maxConnections` when +this occurs. + +### child.stderr + +* {Stream object} + +A `Readable Stream` that represents the child process's `stderr`. + +If the child was spawned with `stdio[2]` set to anything other than `'pipe'`, +then this will be `undefined`. + +`child.stderr` is an alias for `child.stdio[2]`. Both properties will refer to +the same value. + +### child.stdin + +* {Stream object} + +A `Writable Stream` that represents the child process's `stdin`. + +*Note that if a child process waits to read all of its input, the child will not +continue until this stream has been closed via `end()`.* + +If the child was spawned with `stdio[0]` set to anything other than `'pipe'`, +then this will be `undefined`. + +`child.stdin` is an alias for `child.stdio[0]`. Both properties will refer to +the same value. + +### child.stdio + +* {Array} + +A sparse array of pipes to the child process, corresponding with positions in +the [`stdio`][] option passed to [`child_process.spawn()`][] that have been set +to the value `'pipe'`. Note that `child.stdio[0]`, `child.stdio[1]`, and +`child.stdio[2]` are also available as `child.stdin`, `child.stdout`, and +`child.stderr`, respectively. + +In the following example, only the child's fd `1` (stdout) is configured as a +pipe, so only the parent's `child.stdio[1]` is a stream, all other values in +the array are `null`. + + const assert = require('assert'); + const fs = require('fs'); + const child_process = require('child_process'); + + const child = child_process.spawn('ls', { + stdio: [ + 0, // Use parents stdin for child + 'pipe', // Pipe child's stdout to parent + fs.openSync('err.out', 'w') // Direct child's stderr to a file + ] + }); + + assert.equal(child.stdio[0], null); + assert.equal(child.stdio[0], child.stdin); + + assert(child.stdout); + assert.equal(child.stdio[1], child.stdout); + + assert.equal(child.stdio[2], null); + assert.equal(child.stdio[2], child.stderr); + +### child.stdout + +* {Stream object} + +A `Readable Stream` that represents the child process's `stdout`. + +If the child was spawned with `stdio[1]` set to anything other than `'pipe'`, +then this will be `undefined`. + +`child.stdout` is an alias for `child.stdio[1]`. Both properties will refer +to the same value. + +[`popen(3)`]: http://linux.die.net/man/3/popen [`child_process.exec()`]: #child_process_child_process_exec_command_options_callback +[`child_process.execFile()`]: #child_process_child_process_execfile_file_args_options_callback [`child_process.fork()`]: #child_process_child_process_fork_modulepath_args_options [`child_process.spawn()`]: #child_process_child_process_spawn_command_args_options [`child_process.spawnSync()`]: #child_process_child_process_spawnsync_command_args_options [`ChildProcess#kill()`]: #child_process_child_kill_signal [`ChildProcess#send()`]: #child_process_child_send_message_sendhandle_callback [`Error`]: errors.html#errors_class_error -[`EventEmitter`]: events.html#events_class_events_eventemitter -[`exec()`]: #child_process_child_process_exec_command_options_callback -[`execFile()`]: #child_process_child_process_execfile_file_args_options_callback -[`fork()`]: #child_process_child_process_fork_modulepath_args_options +[`EventEmitters`]: events.html#events_class_events_eventemitter [`net.Server`]: net.html#net_class_net_server [`net.Socket`]: net.html#net_class_net_socket -[`spawn()`]: #child_process_child_process_spawn_command_args_options [`stdio`]: #child_process_options_stdio [below]: #child_process_asynchronous_process_creation [synchronous counterparts]: #child_process_synchronous_process_creation -- 2.7.4