Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/kpdecker/forever into v0.5.x
Browse files Browse the repository at this point in the history
  • Loading branch information
indexzero committed Apr 19, 2011
2 parents 7089311 + 95434b3 commit 3beb6da
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 25 deletions.
41 changes: 26 additions & 15 deletions bin/forever
Expand Up @@ -13,7 +13,7 @@ if (accepts.indexOf(process.argv[2]) !== -1) {
var argv = require('optimist').argv;
require.paths.unshift(path.join(__dirname, '..', 'lib'));

var forever = require('forever');
var forever = require('../lib/forever');

var help = [
"usage: forever [start | stop | restart | stopall | list | cleanlogs] [options] SCRIPT [script options]",
Expand All @@ -26,16 +26,18 @@ var help = [
" 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",
" -m MAX Only run the specified script MAX times",
" -l LOGFILE Logs the forever output to LOGFILE",
" -a, --append Append logs",
" -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)",
" --pidfile=PIDFILE The pid file",
" -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.",
Expand All @@ -55,9 +57,12 @@ var mappings = {
'e': 'errFile',
'd': 'sourceDir',
'l': 'logFile',
'a': 'appendLog',
'append': 'appendLog',
'm': 'max',
'o': 'outFile',
'p': 'path',
'pidfile': 'pidFile',
's': 'silent',
'silent': 'silent',
'v': 'verbose',
Expand Down Expand Up @@ -106,6 +111,11 @@ if (!options.sourceDir) {
options.sourceDir = file && file[0] !== '/' ? process.cwd() : '/';
}

// Pass the source dir to spawn
options.spawnWith = {
cwd: options.sourceDir
};

//
// Configure winston for forever based on the CLI options
//
Expand All @@ -123,15 +133,16 @@ var config = {
function tryStart (callback) {
var fullLog, fullScript, uid = forever.randomString(16);
options.uid = uid;
options.pidFile = 'forever' + uid + '.pid';
options.pidFile = options.pidFile || 'forever' + uid + '.pid';
options.logFile = argv.l || 'forever' + uid + '.log';
fullLog = path.join(forever.config.root, options.logFile);

fullLog = forever.logFilePath(options.logFile);
fullScript = path.join(options.sourceDir, file);

forever.stat(fullLog, fullScript, function (err) {
forever.stat(fullLog, fullScript, options.appendLog, function (err) {
if (err) {
winston.error('Cannot start forever: ' + err.message);
process.exit(0);
process.exit(-1);
}

callback();
Expand Down
96 changes: 96 additions & 0 deletions examples/initd-example
@@ -0,0 +1,96 @@
#!/bin/bash
#
# initd-example Node init.d
#
# chkconfig: 345 80 20
# description: Node init.d example
# processname: node
# pidfile: /var/run/initd-example.pid
# logfile: /var/log/initd-example.log
#

# Source function library.
. /etc/init.d/functions

NAME=initd-example # Unique name for the application
PORT=1234 # Port (in this case the application uses process.env.PORT to set the port)
INSTANCE_DIR=/var/www/$NAME # Location of the application source
SOURCE_NAME=main.js # Name os the applcation entry point script

user=apache
pidfile=/var/run/$NAME.pid
logfile=/var/log/$NAME.log
forever_dir=/var/run/forever # Forever root directory.

node=node
forever=forever
awk=awk
sed=sed

start() {
echo "Starting $NAME node instance: "

if [ "$id" = "" ]; then
# Create the log and pid files, making sure that the target use has access to them
touch $logfile
chown $user $logfile

touch $pidfile
chown $user $pidfile

# Launch the application
daemon --user=$user \
env PORT=$PORT \
$forever start -p $forever_dir --pidfile $pidfile -l $logfile -a -d $INSTANCE_DIR $SOURCE_NAME
RETVAL=$?
else
echo "Instance already running"
RETVAL=0
fi
}

restart() {
echo -n "Restarting $NAME node instance : "
if [ "$id" != "" ]; then
$forever restart -p $forever_dir $id
RETVAL=$?
else
start
fi
}

stop() {
echo -n "Shutting down $NAME node instance : "
if [ "$id" != "" ]; then
$forever stop -p $forever_dir $id
else
echo "Instance is not running";
fi
RETVAL=$?
}

getForeverId() {
local pid=$(pidofproc -p $pidfile)
$forever list -p $forever_dir | $sed -e 's/\x1b\[[0-9; ]*m//g' | $awk "\$4 == \"$pid]\" { gsub(/[\[\]]/, \"\", \$1); print \$1; }"
}
id=$(getForeverId)

case "$1" in
start)
start
;;
stop)
stop
;;
status)
status -p ${pidfile}
;;
restart)
restart
;;
*)
echo "Usage: {start|stop|status|restart}"
exit 1
;;
esac
exit $RETVAL
64 changes: 54 additions & 10 deletions lib/forever.js
Expand Up @@ -76,17 +76,31 @@ forever.load();
//
// ### function stat (logFile, script, callback)
// #### @logFile {string} Path to the log file for this script
// #### @logAppend {boolean} Optional. True Prevent failure if the log file exists.
// #### @script {string} Path to the target script.
// #### @callback {function} Continuation to pass control back to
// Ensures that the logFile doesn't exist and that
// the target script does exist before executing callback.
//
forever.stat = function (logFile, script, callback) {
fs.stat(logFile, function (err, stats) {
if (!err) return callback(new Error('log file ' + logFile + ' exists.'));
fs.stat(script, function (err, stats) {
if (err) return callback(new Error('script ' + script + ' does not exist.'));
callback(null);
var logAppend,
realCallback = callback;
if (arguments.length === 4) {
logAppend = callback;
realCallback = arguments[3];
}

fs.stat(script, function (err, stats) {
if (err) return realCallback(new Error('script ' + script + ' does not exist.'));

if (logAppend) {
realCallback(null);
return;
}

fs.stat(logFile, function (err, stats) {
if (!err) return realCallback(new Error('log file ' + logFile + ' exists.'));
realCallback(null);
});
});
};
Expand All @@ -108,21 +122,25 @@ forever.start = function (script, options) {
// Starts a script with forever as a daemon
//
forever.startDaemon = function (script, options) {
options.logFile = path.join(config.root, options.logFile || 'forever.log');
options.pidFile = path.join(config.pidPath, options.pidFile);
options.logFile = forever.logFilePath(options.logFile);
options.pidFile = forever.pidFilePath(options.pidFile);
var runner = new forever.Monitor(script, options);

daemon.daemonize(options.logFile, options.pidFile, function (err, pid) {

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


var pid = daemon.start(fd);
daemon.lock(options.pidFile);

//
// Remark: This should work, but the fd gets screwed up
// with the daemon process.
//
// process.on('exit', function () {
// fs.unlinkSync(options.pidFile);
// });

process.pid = pid;
runner.start();
});
Expand Down Expand Up @@ -387,6 +405,32 @@ forever.randomString = function (bits) {
return ret;
};

//
// ### function logFilePath (logFile)
// #### @logFile {string} Log file path
// Determines the full logfile path name
//
forever.logFilePath = function(logFile) {
if (logFile && logFile[0] === "/") {
return logFile;
} else {
return path.join(forever.config.root, logFile || "forever.log");
}
};

//
// ### function pidFilePath (pidFile)
// #### @logFile {string} Pid file path
// Determines the full pid file path name
//
forever.pidFilePath = function(pidFile) {
if (pidFile && pidFile[0] === "/") {
return pidFile;
} else {
return path.join(config.pidPath, pidFile);
}
};

//
// ### function checkProcess (pid, callback)
// #### @pid {string} pid of the process to check
Expand Down

0 comments on commit 3beb6da

Please sign in to comment.