Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 227 lines (199 sloc) 6.882 kb
#!/usr/bin/env node
var path = require('path'),
fs = require('fs'),
eyes = require('eyes'),
winston = require('winston'),
sys = require('sys');
var accepts = ['start', 'stop', 'stopall', 'list', 'cleanlogs', 'restart'], action;
if (accepts.indexOf(process.argv[2]) !== -1) {
action = process.argv.splice(2,1)[0];
}
var argv = require('optimist').argv;
require.paths.unshift(path.join(__dirname, '..', 'lib'));
var forever = require('forever');
var help = [
"usage: forever [start | stop | restart | stopall | list | cleanlogs] [options] SCRIPT [script options]",
"",
"options:",
" start start SCRIPT as a daemon",
" stop stop the daemon SCRIPT",
" stopall stop all running forever scripts",
" restart restart the daemon SCRIPT",
" list list all running forever scripts",
" cleanlogs [CAREFUL] Deletes all historical forever log files",
"",
" -m MAX Only run the specified script MAX times",
" -l LOGFILE Logs the forever output to LOGFILE",
" -o OUTFILE Logs stdout from child script to OUTFILE",
" -e ERRFILE Logs stderr from child script to ERRFILE",
" -d SOURCEDIR The source directory for which SCRIPT is relative to",
" -p PATH Base path for all forever related files (pid files, etc.)",
" -c COMMAND COMMAND to execute (defaults to node)",
" -v, --verbose Turns on the verbose messages from Forever",
" -s, --silent Run the child script silencing stdout and stderr",
" -h, --help You're staring at it",
"",
"[Long Running Process]",
" The forever process will continue to run outputting log messages to the console.",
" ex. forever -o out.log -e err.log my-script.js",
"",
"[Daemon]",
" The forever process will run as a daemon which will make the target process start",
" in the background. This is extremely useful for remote starting simple node.js scripts",
" without using nohup. It is recommended to run start with -o -l, & -e.",
" ex. forever start -l forever.log -o out.log -e err.log my-daemon.js",
" forever stop my-daemon.js",
""
].join('\n');
var mappings = {
'c': 'command',
'e': 'errFile',
'd': 'sourceDir',
'l': 'logFile',
'm': 'max',
'o': 'outFile',
'p': 'path',
's': 'silent',
'silent': 'silent',
'v': 'verbose',
'verbose': 'verbose'
};
function isSimpleAction () {
return ['list', 'stopall', 'cleanlogs'].indexOf(action) !== -1;
};
// Show help prompt if requested or if the
// incorrect usage options are supplied
if (argv.h || argv.help ||
(argv._.length === 0 && !isSimpleAction())) {
sys.puts(help);
return;
}
// If we are passed more than one non-hyphenated
// options, only use the first one. Assume the
// rest are pass-through for the child process
var file = argv._[0], options = {};
// Setup pass-thru options for child-process
if (file) {
options.options = process.argv.splice(process.argv.indexOf(file)).splice(1);
}
// Now that we've removed the target script options
// reparse the options and configure the forever settings
argv = require('optimist')(process.argv).argv;
Object.keys(argv).forEach(function (key) {
if (mappings[key]) {
options[mappings[key]] = argv[key];
}
});
// If max isn't specified set it to run forever
if (typeof options['max'] === 'undefined') {
options.forever = true;
}
// Set the sourceDir of the options for graceful
// restarting outside of the main directory
if (!options.sourceDir) {
options.sourceDir = file && file[0] !== '/' ? process.cwd() : '/';
}
//
// Configure winston for forever based on the CLI options
//
winston.defaultTransports().console.timestamp = false;
winston.defaultTransports().console.colorize = true;
if (options.verbose) {
winston.defaultTransports().console.level = 'silly';
}
// Setup configurations for forever
var config = {
root: argv.p
};
function tryStart (callback) {
var fullLog, fullScript, uid = forever.randomString(16);
options.uid = uid;
options.pidFile = 'forever' + uid + '.pid';
options.logFile = argv.l || 'forever' + uid + '.log';
fullLog = path.join(forever.config.root, options.logFile);
fullScript = path.join(options.sourceDir, file);
forever.stat(fullLog, fullScript, function (err) {
if (err) {
winston.error('Cannot start forever: ' + err.message);
process.exit(0);
}
callback();
});
}
//
// Only call `forever.load()` if the root path is different than
// the default root exposed by forever.
//
if (config.root && config.root !== forever.root) {
winston.silly('Loading forever with config: ', config);
forever.load(config);
winston.silly('Loaded forever successfully.');
}
winston.silly('Tidying ' + forever.config.root);
var tidy = forever.cleanUp(action === 'cleanlogs');
tidy.on('cleanUp', function () {
winston.silly(forever.config.root + ' tidied.');
if (file) {
winston.info('Forever processing arguments', { arg: file });
}
if (options) {
winston.silly('Forever using options', options);
}
if (action) {
winston.info('Running action: ' + action.yellow);
switch (action) {
case 'start':
tryStart(function () { forever.startDaemon(file, options); });
break;
case 'stop':
var runner = forever.stop(file, true);
runner.on('stop', function (process) {
winston.info('Forever stopped process:');
sys.puts(process);
});
runner.on('error', function (err) {
winston.error('Forever cannot find process with index: ' + file)
})
break;
case 'stopall':
var runner = forever.stopAll(true);
runner.on('stopAll', function (processes) {
if (processes) {
winston.info('Forever stopped processes:');
sys.puts(processes);
}
else {
winston.info('No forever processes running');
}
});
break;
case 'restart':
var runner = forever.restart(file, true);
runner.on('restart', function (processes) {
if (processes) {
winston.info('Forever restarted processes:');
sys.puts(processes);
}
else {
winston.info('No forever processes running');
}
});
break;
case 'list':
var processes = forever.list(true);
if (processes) {
winston.info('Forever processes running');
sys.puts(processes);
}
else {
winston.info('No forever processes running');
}
break;
}
}
else {
tryStart(function () {
forever.start(file, options);
});
}
});
Jump to Line
Something went wrong with that request. Please try again.