Permalink
Browse files

child_process: expose UV_PROCESS_DETACHED as options.detached

  • Loading branch information...
1 parent 5046f85 commit 4b021a3541770ae64a415760339bdd3223fdf602 @AvianFlu AvianFlu committed with isaacs Jun 1, 2012
@@ -249,7 +249,7 @@ there is no IPC channel keeping it alive. When calling this method the
* `customFds` {Array} **Deprecated** File descriptors for the child to use
for stdio. (See below)
* `env` {Object} Environment key-value pairs
- * `setsid` {Boolean}
+ * `detached` {Boolean} The child will be a process group leader. (See below)
* return: {ChildProcess object}
Launches a new process with the given `command`, with command line arguments in `args`.
@@ -342,7 +342,7 @@ index corresponds to a fd in the 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
- child_process object as `ChildProcess.stdio[fd]`. Pipes created for
+ `child_process` object as `ChildProcess.stdio[fd]`. Pipes created for
fds 0 - 2 are also available as ChildProcess.stdin, ChildProcess.stdout
and ChildProcess.stderr, respectively.
2. `'ipc'` - Create an IPC channel for passing messages/file descriptors
@@ -387,6 +387,34 @@ Example:
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });
+If the `detached` option is set, the child process will be made the leader of a
+new process group. This makes it possible for the child to continue running
+after the parent exits.
+
+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.
+
+Example of detaching a long-running process and redirecting its output to a
+file:
+
+ var fs = require('fs'),
+ spawn = require('child_process').spawn,
+ out = fs.openSync('./out.log', 'a'),
+ err = fs.openSync('./out.log', 'a');
+
+ var child = spawn('prg', [], {
+ detached: 'true',
+ stdio: [ 'ignore', out, err ]
+ });
+
+ child.unref();
+
+When using the `detached` option to start a long-running process, the process
+will not stay running in the background unless it is provided with a `stdio`
OrangeDog
OrangeDog Jun 11, 2012

running in the background after the parent exits is the correct reading?

+configuration that is not connected to the parent. If the parent's `stdio` is
+inherited, the child will remain attached to the controlling terminal.
+
There is a deprecated option called `customFds` which allows one to specify
specific file descriptors for the stdio of the child process. This API was
not portable to all platforms and therefore removed.
@@ -409,7 +437,6 @@ See also: `child_process.exec()` and `child_process.fork()`
* `customFds` {Array} **Deprecated** File descriptors for the child to use
for stdio. (See above)
* `env` {Object} Environment key-value pairs
- * `setsid` {Boolean}
* `encoding` {String} (Default: 'utf8')
* `timeout` {Number} (Default: 0)
* `maxBuffer` {Number} (Default: 200*1024)
@@ -467,7 +494,6 @@ the child process is killed.
* `customFds` {Array} **Deprecated** File descriptors for the child to use
for stdio. (See above)
* `env` {Object} Environment key-value pairs
- * `setsid` {Boolean}
* `encoding` {String} (Default: 'utf8')
* `timeout` {Number} (Default: 0)
* `maxBuffer` {Number} (Default: 200*1024)
@@ -490,7 +516,6 @@ leaner than `child_process.exec`. It has the same options.
* `options` {Object}
* `cwd` {String} Current working directory of the child process
* `env` {Object} Environment key-value pairs
- * `setsid` {Boolean}
* `encoding` {String} (Default: 'utf8')
* `timeout` {Number} (Default: 0)
* Return: ChildProcess object
View
@@ -602,12 +602,17 @@ var spawn = exports.spawn = function(file, args, options) {
args: args,
cwd: options ? options.cwd : null,
windowsVerbatimArguments: !!(options && options.windowsVerbatimArguments),
+ detached: !!(options && options.detached),
envPairs: envPairs,
stdio: options ? options.stdio : null,
uid: options ? options.uid : null,
gid: options ? options.gid : null
});
+ if (options && options.detached) {
+ child.unref();
AndreasMadsen
AndreasMadsen Jun 11, 2012 Member

The doc says that I should call child.unref() to completely deattach the the child from its parent. However this automatically done here. Are I'm correct in assuming that it is necessary to call child.unref() twice from a core perspective or is this a bug (in doc or code).

@AvianFlu this is so awesome thanks.

isaacs
isaacs Jun 11, 2012

Ah, yes, that's a mistake on my part, I believe. I'll remove it. It'll be fixed in the next release.

+ }
+
return child;
};
View
@@ -236,6 +236,11 @@ class ProcessWrap : public HandleWrap {
options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
}
+ //options.detached
+ if (js_options->Get(String::NewSymbol("detached"))->IsTrue()) {
+ options.flags |= UV_PROCESS_DETACHED;
+ }
+
int r = uv_spawn(uv_default_loop(), &wrap->process_, options);
if (r) {
@@ -0,0 +1 @@
+setInterval(function () {}, 500);
@@ -0,0 +1,38 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var assert = require('assert');
+var path = require('path');
+
+var spawn = require('child_process').spawn;
+var childPath = path.join(__dirname, '..', 'fixtures', 'child-process-persistent.js');
+
+var child = spawn(process.execPath, [ childPath ], {
+ detached: true,
+ stdio: 'ignore'
+});
+
+process.on('exit', function () {
+ process.kill(child.pid);
+ assert.throws(process.kill(child.pid), Error);
+});
+

3 comments on commit 4b021a3

What is the 'ignore' option to stdio, input stream? Would it be better to use null?

Owner

'null' or 'undefined' are default values for stdio option, that means that for stdio < 3 (i.e. stdin, stdout, stderr) it'll create 'pipe' and for others 'ignore'.

@shtylman - The new stdio API for child processes allows for a couple of shorthands - if you pass only the string ignore, all three stdio will be redirected to /dev/null, or the windows equivalent. Where this test is concerned, it was used for simplicity.

Please sign in to comment.