Skip to content
Browse files

Release v0.0.15

  • Loading branch information...
2 parents d7a8dca + c3473f9 commit 1907a61db99225ab0d4d30dec93ab6a5ccf14fc6 @pgte committed Oct 2, 2010
Showing with 95 additions and 58 deletions.
  1. +18 −0 LICENSE
  2. +76 −57 lib/fugue.js
  3. +1 −1 package.json
View
18 LICENSE
@@ -0,0 +1,18 @@
+Copyright 2010 Pedro Teixeira. All rights reserved.
+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.
View
133 lib/fugue.js
@@ -26,15 +26,15 @@ var stop = exports.stop = function() {
exports.start = function(server, port, host, worker_count, options) {
function isPort (x) { return parseInt(x) >= 0; }
-
+
var unix_socket_path = null;
if (!isPort(port)) {
// shift arguments
in_options = worker_count;
worker_count = host;
unix_socket_path = port;
}
-
+
// merge options
var default_options = {
working_path : process.cwd(),
@@ -50,34 +50,34 @@ exports.start = function(server, port, host, worker_count, options) {
})(default_options, options);
}
options = default_options;
-
+
var path = require('path');
// check if paths exist
if (!path.existsSync(options.tmp_path)) {
- throw "Temp path "+options.tmp_path + " does not exist. Please create it";
+ throw "Temp path " + options.tmp_path + " does not exist. Please create it";
}
if (!path.existsSync(options.working_path)) {
- throw "Working path "+options.working_path + " does not exist. Please create it";
+ throw "Working path " + options.working_path + " does not exist. Please create it";
}
-
+
// setup log function
- var log = function(what) {
- if (options.verbose) console.log(what);
- }
+ var log = options.verbose ?
+ function(what) { console.log(what); } :
+ function() {};
// Master or worker?
var worker_id = process.env._FUGUE_WORKER;
var is_master = !worker_id;
// daemonize?
if (is_master && options.daemonize) {
- log('daemonizing '+process.pid);
- daemon = require(__dirname+'/../build/default/daemon');
+ log('daemonizing ' + process.pid);
+ daemon = require(__dirname + '/../build/default/daemon');
daemon.setSid();
log('daemonized');
}
-
+
// require needed modules
var net = require('net'),
http = require('http'),
@@ -91,7 +91,7 @@ exports.start = function(server, port, host, worker_count, options) {
if (options.log_file) {
process.stdout.fd = fs.openSync(options.log_file, 'a');
}
-
+
// calculate master_socket_path.
// It can come from env if we have been spawned or we have to create a new one
var master_socket_path = null;
@@ -102,20 +102,20 @@ exports.start = function(server, port, host, worker_count, options) {
}
if (!master_socket_path) {
// make new
- master_socket_path = process.env._FUGUE_MASTER_SOCKET_PATH = path.join(options.tmp_path, 'fugue_'+process.pid+'_master.sock');
+ master_socket_path = process.env._FUGUE_MASTER_SOCKET_PATH = path.join(options.tmp_path, 'fugue_' + process.pid + '_master.sock');
}
-
- log('Using master socket path: '+master_socket_path);
+
+ log('Using master socket path: ' + master_socket_path);
if (is_master) { // Master
-
+
// If we are respawned from another master we have to setsid anyway
if (process.env._FUGUE_ORIG_MASTER_PID) {
- daemon = require(__dirname+'/../build/default/daemon');
+ daemon = require(__dirname + '/../build/default/daemon');
daemon.setSid();
}
log('Starting new master...');
-
+
if (options.master_log_file) {
process.stdout.fd = fs.openSync(options.master_log_file, 'w');
}
@@ -126,7 +126,7 @@ exports.start = function(server, port, host, worker_count, options) {
// request socket to original server
// this startup part has to work synchronously, so we dig deep into the bindings...
var client_socket = netBinding.socket('unix');
- log('connecting to '+master_socket_path);
+ log('connecting to ' + master_socket_path);
netBinding.connect(client_socket, master_socket_path);
var request_buffer = new Buffer('GIMME_SOCKET', 'ascii');
netBinding.write(client_socket, request_buffer, 0, request_buffer.length);
@@ -135,48 +135,48 @@ exports.start = function(server, port, host, worker_count, options) {
do {
length = netBinding.recvMsg(client_socket, responseBuffer, 0, responseBuffer.length)
} while(!netBinding.recvMsg.fd);
-
- log('Got response from server:'+responseBuffer.toString('ascii', 0, length));
+
+ log('Got response from server:' + responseBuffer.toString('ascii', 0, length));
if (netBinding.recvMsg.fd) {
server_socket = netBinding.recvMsg.fd;
} else {
log('Response got no file descriptor... (bad)');
}
} catch(error) {
- log('Error trying to get server file descriptor: '+error.message);
+ log('Error trying to get server file descriptor: ' + error.message);
}
if (!server_socket) {
log('Failed to get socket from original server.');
log('Now I\'m going to try to create one...')
}
-
+
}
if (!server_socket) {
// Now we have to create a socket
if (unix_socket_path) {
- // UNIX socket
-
+ // UNIX socket
+
// remove socket file if it exists
try {
fs.unlinkSync(unix_socket_path);
} catch(err) {
// do nothing, file does not exist
}
-
+
server_socket = netBinding.socket('unix');
netBinding.bind(server_socket, unix_socket_path);
process.env._FUGUE_SOCKET = unix_socket_path;
} else {
// TCP socket
- server_socket = netBinding.socket('tcp'+(netBinding.isIP(host) == 6 ? 6 : 4));
+ server_socket = netBinding.socket('tcp' + (netBinding.isIP(host) == 6 ? 6 : 4));
netBinding.bind(server_socket, port, host);
process.env._FUGUE_PORT = port;
process.env._FUGUE_HOST = host;
}
netBinding.listen(server_socket, 128);
}
-
+
log('Have server socket: ' + server_socket);
var fd_server = net.createServer(function(conn) {
@@ -185,11 +185,12 @@ exports.start = function(server, port, host, worker_count, options) {
if (data.toString() == 'GIMME_SOCKET') {
log('serving server socket file descriptor ' + server_socket);
conn.write('HERE_YOU_GO', 'ascii', server_socket);
- }
+ }
});
}).listen(master_socket_path);
-
+ var workers = [];
+
var spawn_worker = function(worker_idx) {
// prepare environment for worker
var env = {};
@@ -204,34 +205,53 @@ exports.start = function(server, port, host, worker_count, options) {
if(!options.log_file) {
// if worker does not log into file, pipe the worker output here
var worker_log = function(what) {
- log("WORKER "+worker_idx+ ": " + what.toString());
+ log("WORKER " + worker_idx + ": " + what.toString());
}
- new_worker.stdout.on('data', worker_log);
+ new_worker.stdout.on('data', worker_log);
new_worker.stderr.on('data', worker_log);
}
-
+
// listen for when the worker dies and bring him back to life
new_worker.on('exit', function() {
- log('Child '+worker_idx+' died. Respawning it.');
+ log('Child ' + worker_idx + ' died. Respawning it.');
spawn_worker(worker_idx);
});
-
+
}
-
+
// fork workers
log('Spawning workers...');
process.env._FUGUE_WORKER_COUNT = worker_count;
for (var worker_idx = 0; worker_idx < worker_count; worker_idx ++) {
spawn_worker(worker_idx);
}
log('spawned.')
-
+
+ var killer = function() {
+ log('exiting.');
+ for(var i in workers) {
+ var worker = workers[i];
+ worker.removeAllListeners(); // Prevent from master respawn
+ try {
+ worker.kill();
+ } catch(excep) {
+ // do nothing, as the error is probably that the process does no longer exist
+ }
+ }
+ workers = [];
+ netBinding.close(server_socket);
+ process.removeAllListeners();
+ process.nextTick(function() {
+ process.exit();
+ });
+ }
+
// Listen for process exits
// process.on('exit', world_killer);
- process.on('SIGINT', stop);
- process.on('SIGHUP', stop);
- process.on('SIGTERM', stop);
-
+ process.on('SIGINT', killer);
+ process.on('SIGHUP', killer);
+ process.on('SIGTERM', killer);
+
// Listen to SIGUSR2 for master restarts
process.on('SIGUSR2', function() {
log('Got SIGUSR2, respawning self');
@@ -242,37 +262,36 @@ exports.start = function(server, port, host, worker_count, options) {
}
env._FUGUE_ORIG_MASTER_PID = process.pid.toString();
var args = process.argv;
-
+
// spawn worker process
spawned = spawn(args[0], args.slice(1), env);
spawned.stdout.on('data', function(data) {
- log("New master goes: "+data);
+ log("New master goes: " + data);
});
-
+
});
-
+
// Save master PID
if (options.master_pid_path) {
fs.writeFile(options.master_pid_path, process.pid.toString(), function(error) {
- if (error) throw "Error saving master PID file in "+options.master_pid_path+': '+error;
+ if (error) throw "Error saving master PID file in " + options.master_pid_path + ': ' + error;
});
}
-
} else { // Worker
-
+
log('Worker here');
-
+
// track connections here
var connection_count = 0;
-
+
var die_soon = false; // tells if worker should die after serving exisiting connections
// Setup killer
var worker_killer = function() {
if(connection_count == 0) {
process.nextTick(function() {
process.exit();
- });
+ });
} else {
// Stop listening for new connections - remove watcher from the event loop
server.watcher.stop();
@@ -283,9 +302,9 @@ exports.start = function(server, port, host, worker_count, options) {
process.on('SIGINT', worker_killer);
process.on('SIGHUP', worker_killer);
process.on('SIGTERM', worker_killer);
-
+
process.on('exit', function() {
- log("Worker "+worker_id+" exiting.");
+ log("Worker " + worker_id + " exiting.");
});
var connection = net.createConnection(master_socket_path).on('connect', function() {
@@ -298,7 +317,7 @@ exports.start = function(server, port, host, worker_count, options) {
log('killing original master');
process.kill(kill_master_pid);
}
-
+
// change working dir
if (process.cwd() != options.working_path) {
process.chdir(options.working_path);
@@ -312,11 +331,11 @@ exports.start = function(server, port, host, worker_count, options) {
process.setuid(options.uid);
}
- server.listenFD(fd);
+ server.listenFD(fd);
});
});
-
+
// Track connections so we don't die in the middle of serving one
server.on('connection', function(connection) {
connection_count ++;
View
2 package.json
@@ -1,6 +1,6 @@
{ "name" : "fugue"
, "description" : "Unicorn for node for node"
-, "version" : "0.0.14"
+, "version" : "0.0.15"
, "homepage" : "http://www.metaduck.com/fugue"
, "author" : "Pedro Teixeira <pedro.teixeira@gmail.com> (http://www.metaduck.com)"
, "contributors" :

0 comments on commit 1907a61

Please sign in to comment.
Something went wrong with that request. Please try again.