From b06d58b20b69be8342a66c34df7bf3b2cfa43936 Mon Sep 17 00:00:00 2001 From: indexzero Date: Mon, 2 Jan 2012 23:37:58 -0500 Subject: [PATCH] [api] Expose `Monitor.fork` for using `child_process.fork()` --- lib/forever/monitor.js | 66 ++++++++++++++++++++++++++++++++---------- test/fork-test.js | 9 +++--- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/lib/forever/monitor.js b/lib/forever/monitor.js index 9e69316d..c7973c93 100644 --- a/lib/forever/monitor.js +++ b/lib/forever/monitor.js @@ -158,17 +158,17 @@ Monitor.prototype.start = function (restart) { self.emit(restart ? 'restart' : 'start', self, self.data); }); - function reemit() { - self.emit.apply(self, arguments); + function onMessage(msg) { + self.emit('message', msg); } // Re-emit messages from the child process - this.child.on('message', reemit); + this.child.on('message', onMessage); child.on('exit', function (code) { var spinning = Date.now() - self.ctime < self.minUptime; self.warn('Forever detected script exited with code: ' + code); - child.removeListener('message', reemit); + child.removeListener('message', onMessage); function letChildDie() { self.running = false; @@ -210,9 +210,6 @@ Monitor.prototype.start = function (restart) { // trying to execute a script with an env: e.g. node myfile.js // Monitor.prototype.trySpawn = function () { - var execPath = process.execPath, - forked; - if (this.command === 'node' || (this.checkFile && !this.childExists)) { try { var stats = fs.statSync(this.args[0]); @@ -226,14 +223,9 @@ Monitor.prototype.trySpawn = function () { this.spawnWith.cwd = this.cwd || this.spawnWith.cwd; this.spawnWith.env = this._getEnv(); - if (this.command === 'node' || this.fork) { - process.execPath = this.command; - forked = fork(this.options[0], this.options.slice(1), this.spawnWith); - process.execPath = execPath; - return forked; - } - - return spawn(this.command, this.options, this.spawnWith); + return this.fork + ? this._forkSpawn() + : spawn(this.command, this.options, this.spawnWith); }; // @@ -402,3 +394,47 @@ Monitor.prototype._getEnv = function () { return merged; }; + +// +// ### @private function _forkSpawn() +// +// This is an unfortunate hack which works around two inconsistencies +// in the `child_process` APIs in node.js core as of `v0.6.6`. Pull-requests +// are open to resolve both issues. +// +// https://github.com/joyent/node/pull/2455 +// https://github.com/joyent/node/pull/2454 +// +// Until then, setup `options.customFds` to always return null. +// +// +Monitor.prototype._forkSpawn = function () { + var execPath = process.execPath, + hackSpawn = {}, + self = this, + forked; + + if (this.spawnWith && typeof this.spawnWith === 'object') { + Object.keys(this.spawnWith).forEach(function (key) { + hackSpawn[key] = self.spawnWith[key]; + }); + } + + delete hackSpawn.customFds; + Object.defineProperty(hackSpawn, 'customFds', { + get: function () { + return null; + }, + set: function () { + // + // Do nothing, ignore the attempt to overwrite here: + // https://github.com/joyent/node/blob/master/lib/child_process.js#L172 + // + } + }); + + process.execPath = this.command; + forked = fork(this.options[0], this.options.slice(1), hackSpawn); + process.execPath = execPath; + return forked; +}; diff --git a/test/fork-test.js b/test/fork-test.js index 5b669e04..b7c15df9 100644 --- a/test/fork-test.js +++ b/test/fork-test.js @@ -11,18 +11,19 @@ var assert = require('assert'), vows = require('vows'), forever = require('../lib/forever'); -vows.describe('forever/spin-restart').addBatch({ +vows.describe('forever/fork').addBatch({ "When using forever": { "and spawning a script that uses `process.send()`": { topic: function () { var script = path.join(__dirname, '..', 'examples', 'process-send.js'), - child = new (forever.Monitor)(script, { silent: true, minUptime: 2000, max: 1 }); + child = new (forever.Monitor)(script, { silent: false, minUptime: 2000, max: 1, fork: true }); child.on('message', this.callback.bind(null, null)); child.start(); }, - "should reemit the message correctly": function (err, child, spinning) { - console.dir(arguments); + "should reemit the message correctly": function (err, msg) { + assert.isObject(msg); + assert.deepEqual(msg, { from: 'child' }); } } }