Skip to content

Commit

Permalink
[api test] Update to use nconf for forever configuration. Use uids fo…
Browse files Browse the repository at this point in the history
…r filenames instead of forever* and forever pids (more defensive + support for multiple monitors from a single `forever` process).
  • Loading branch information
indexzero committed Apr 20, 2011
1 parent be6de72 commit 1c16e81
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 53 deletions.
11 changes: 6 additions & 5 deletions bin/forever
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ var config = {
};

function tryStart (callback) {
var fullLog, fullScript, uid = forever.randomString(16);
var fullLog, fullScript, uid = forever.randomString(24);
options.uid = uid;
options.pidFile = options.pidFile || 'forever' + uid + '.pid';
options.logFile = argv.l || 'forever' + uid + '.log';
options.pidFile = options.pidFile || uid + '.pid';
options.logFile = argv.l || uid + '.log';

fullLog = forever.logFilePath(options.logFile);
fullScript = path.join(options.sourceDir, file);
Expand All @@ -160,10 +160,11 @@ if (config.root && config.root !== forever.root) {
winston.silly('Loaded forever successfully.');
}

winston.silly('Tidying ' + forever.config.root);
winston.silly('Tidying ' + forever.config.get('root'));
var tidy = forever.cleanUp(action === 'cleanlogs');
tidy.on('cleanUp', function () {
winston.silly(forever.config.root + ' tidied.');
winston.silly(forever.config.get('root') + ' tidied.');

if (file) {
winston.info('Forever processing arguments', { arg: file });
}
Expand Down
11 changes: 7 additions & 4 deletions examples/server.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
var sys = require('sys'),
http = require('http');
var sys = require('sys'),
http = require('http'),
argv = require('optimist').argv;

var port = argv.p || argv.port || 80;

http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('hello, i know nodejitsu.')
res.end();
}).listen(8000);
}).listen(port);

/* server started */
sys.puts('> hello world running on port 80');
sys.puts('> hello world running on port ' + port);
65 changes: 37 additions & 28 deletions lib/forever.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ var fs = require('fs'),
events = require('events'),
exec = require('child_process').exec,
timespan = require('timespan'),
nconf = require('nconf'),
daemon = require('daemon');

var forever = exports, config;
var forever = exports;

//
// ### Export Components / Settings
// Export `version` and important Prototypes from `lib/forever/*`
//
forever.version = [0, 4, 0];
forever.initialized = false;
forever.root = path.join('/tmp', 'forever');
forever.root = path.join(process.env.HOME, '.forever');
forever.config = new nconf.stores.File({ file: path.join(forever.root, 'config.json') });
forever.Forever = forever.Monitor = require('forever/monitor').Monitor;

//
Expand All @@ -45,12 +47,13 @@ forever.load = function (options) {
// If forever is initalized and the config directories are identical
// simply return without creating directories
//
if (forever.initialized && forever.config.root === options.root &&
forever.config.pidPath === options.pidPath) {
if (forever.initialized && forever.config.get('root') === options.root &&
forever.config.get('pidPath') === options.pidPath) {
return;
}

forever.config = config = options;
forever.config.set('root', options.root);
forever.config.set('pidPath', options.pidPath);

//
// Syncronously create the `root` directory
Expand All @@ -63,8 +66,8 @@ forever.load = function (options) {
catch (ex) { }
}

tryCreate(config.root);
tryCreate(config.pidPath);
tryCreate(forever.config.get('root'));
tryCreate(forever.config.get('pidPath'));
forever.initialized = true;
};

Expand Down Expand Up @@ -126,8 +129,7 @@ forever.startDaemon = function (script, options) {
options.logFile = forever.logFilePath(options.logFile);
options.pidFile = forever.pidFilePath(options.pidFile);
var runner = new forever.Monitor(script, options);



fs.open(options.logFile, options.appendLog ? 'a+' : 'w+', function (err, fd) {
if (err) return runner.emit('error', err);

Expand Down Expand Up @@ -166,8 +168,11 @@ forever.stop = function (target, format, restart) {

if (procs && procs.length > 0) {
procs.forEach(function (proc) {
process.kill(proc.foreverPid);
process.kill(proc.pid);
try {
process.kill(proc.foreverPid);
process.kill(proc.pid);
}
catch (ex) { }
});

process.nextTick(function () {
Expand Down Expand Up @@ -272,7 +277,10 @@ forever.stopAll = function (format) {
cPids = pids.map(function (pid) { return pid.pid });

fPids.concat(cPids).forEach(function (pid) {
process.kill(pid);
try {
process.kill(pid);
}
catch (ex) { }
});

process.nextTick(function () {
Expand Down Expand Up @@ -339,7 +347,7 @@ forever.cleanUp = function (cleanLogs) {
});
}

fs.unlink(path.join(config.pidPath, proc.foreverPid + '.fvr'), function () {
fs.unlink(path.join(forever.config.get('pidPath'), proc.uid + '.fvr'), function () {
// Ignore errors
});

Expand Down Expand Up @@ -372,12 +380,13 @@ forever.cleanUp = function (cleanLogs) {
// that do not belong to current running forever processes.
//
forever.cleanLogsSync = function (processes) {
var files = fs.readdirSync(config.root),
runningLogs = processes && processes.map(function (p) { return p.logFile.split('/').pop() });
var files = fs.readdirSync(forever.config.get('root')),
running = processes && processes.filter(function (p) { return p && p.logFile }),
runningLogs = running && running.map(function (p) { return p.logFile.split('/').pop() });

files.forEach(function (file) {
if (/\.log$/.test(file) && (!runningLogs || runningLogs.indexOf(file) === -1)) {
fs.unlinkSync(path.join(config.root, file));
fs.unlinkSync(path.join(forever.config.get('root'), file));
}
});
};
Expand Down Expand Up @@ -415,7 +424,7 @@ forever.logFilePath = function(logFile) {
if (logFile && logFile[0] === "/") {
return logFile;
} else {
return path.join(forever.config.root, logFile || "forever.log");
return path.join(forever.config.get('root'), logFile || "forever.log");
}
};

Expand All @@ -428,7 +437,7 @@ forever.pidFilePath = function(pidFile) {
if (pidFile && pidFile[0] === "/") {
return pidFile;
} else {
return path.join(forever.config.pidPath, pidFile);
return path.join(forever.config.get('pidPath'), pidFile);
}
};

Expand Down Expand Up @@ -458,7 +467,7 @@ function formatProcess (proc, index, padding) {
return [' [' + index + ']', proc.file.green]
.concat(proc.options.map(function (opt) { return opt.green }))
.concat([padding + '[' + proc.pid + ',', proc.foreverPid + ']'])
.concat(proc.logFile.magenta)
.concat(proc.logFile ? proc.logFile.magenta : '')
.concat(timespan.fromDates(new Date(proc.ctime), new Date()).toString().yellow)
.join(' ');
};
Expand All @@ -470,24 +479,24 @@ function formatProcess (proc, index, padding) {
//
function getAllProcesses (findDead) {
var results = [], processes = {},
files = fs.readdirSync(config.pidPath);
files = fs.readdirSync(forever.config.get('pidPath'));

if (files.length === 0) return null;

files.forEach(function (file) {
try {
var fullPath = path.join(config.pidPath, file),
var fullPath = path.join(forever.config.get('pidPath'), file),
data = fs.readFileSync(fullPath).toString();

switch (file.match(/\.(\w{3})$/)[1]) {
case 'pid':
var pid = parseInt(data);
if (!processes[pid]) processes[pid] = { foreverPid: pid };
break;
switch (path.extname(file)) {
//case '.pid':
// var pid = parseInt(data);
// if (!processes[pid]) processes[pid] = { foreverPid: pid };
// break;

case 'fvr':
case '.fvr':
var child = JSON.parse(data);
processes[child.foreverPid] = child;
processes[child.pid] = child;
break;
}
}
Expand Down
14 changes: 8 additions & 6 deletions lib/forever/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ var sys = require('sys'),
//
var Monitor = exports.Monitor = function (script, options) {
events.EventEmitter.call(this);

this.silent = options.silent || false;
this.forever = options.forever || false;
this.command = options.command || 'node';
this.sourceDir = options.sourceDir;
this.options = options.options || [];
this.spawnWith = options.spawnWith || null;
this.uid = options.uid || forever.randomString(24);
this.max = options.max;
this.logFile = options.logFile;
this.pidFile = options.pidFile;
this.logFile = options.logFile || path.join(forever.config.get('root'), this.uid + '.log');
this.pidFile = options.pidFile || path.join(forever.config.get('pidPath'), this.uid + '.pid');
this.outFile = options.outFile;
this.errFile = options.errFile;
this.logger = options.logger || new (winston.Logger)({
Expand Down Expand Up @@ -97,7 +98,7 @@ Monitor.prototype.start = function (restart) {
this.child = child;
this.running = true;
this.emit(restart ? 'restart' : 'start', self);
this.save()
this.save();

// Hook all stream data and process it
function listenTo (stream) {
Expand Down Expand Up @@ -179,6 +180,7 @@ Monitor.prototype.save = function () {
}

var childData = {
uid: this.uid,
ctime: this.ctime,
pid: this.child.pid,
foreverPid: process.pid,
Expand All @@ -196,8 +198,8 @@ Monitor.prototype.save = function () {
childData.file = childData.file.replace(this.sourceDir + '/', '');
}

var childPath = path.join(forever.config.pidPath, childData.foreverPid + '.fvr');
fs.writeFile(childPath, JSON.stringify(childData), function (err) {
var childPath = path.join(forever.config.get('pidPath'), this.uid + '.fvr');
fs.writeFile(childPath, JSON.stringify(childData, null, 2), function (err) {
if (err) self.emit('error', err);
self.emit('save', childPath, childData);
});
Expand Down
11 changes: 1 addition & 10 deletions test/forever-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,14 @@ var sys = require('sys'),

vows.describe('forever').addBatch({
"When using forever": {
topic: function () {
forever.load({}, this.callback);
},
"and instance of Forever passed valid options": {
topic: function () {
"should have correct properties set": function () {
var child = new (forever.Forever)('any-file.js', {
max: 10,
silent: true,
options: []
});

// Emit a useless callback since we can't return
// an instance of an events.EventEmitter
child.on('test', this.callback);
child.emit('test', null, child);
},
"should have correct properties set": function (err, child) {
assert.isArray(child.options);
assert.equal(child.max, 10);
assert.isTrue(child.silent);
Expand Down

0 comments on commit 1c16e81

Please sign in to comment.