Comparing version 0.7.1 to 0.7.2
[{ | ||
"name" : "echo", | ||
"script" : "./examples/args.js", | ||
"instances" : "1", | ||
"args" : "['--toto=heya coco', '-d', '1']", | ||
"cron_restart" : "* * * * * *" | ||
"script" : "./examples/echo.js", | ||
"instances" : "1" | ||
},{ | ||
"min_uptime" : "100", | ||
"max_restarts" : "400", | ||
"name" : "auto-kill", | ||
"script" : "./examples/killfaste.js" | ||
},{ | ||
"name" : "api", | ||
@@ -14,0 +7,0 @@ "script" : "./examples/child.js", |
@@ -6,11 +6,14 @@ // | ||
var p = require('path'); | ||
var p = require('path'); | ||
var fs = require('fs'); | ||
var util = require('util'); | ||
// Dont change this or the pm2 could not load custom_options.sh because of | ||
// header in bin/pm2 | ||
DEFAULT_FILE_PATH = p.resolve(process.env.HOME, '.pm2'); | ||
module.exports = { | ||
var default_conf = { | ||
DEFAULT_FILE_PATH : DEFAULT_FILE_PATH, | ||
PM2_LOG_FILE_PATH : p.join(p.resolve(process.env.HOME, '.pm2'), 'pm2.log'), | ||
PM2_PID_FILE_PATH : p.join(p.resolve(process.env.HOME, '.pm2'), 'pm2.pid'), | ||
DEFAULT_PID_PATH : p.join(DEFAULT_FILE_PATH, 'pids'), | ||
@@ -20,2 +23,5 @@ DEFAULT_LOG_PATH : p.join(DEFAULT_FILE_PATH, 'logs'), | ||
SAMPLE_CONF_FILE : '../lib/custom_options.sh', | ||
PM2_CONF_FILE : p.join(DEFAULT_FILE_PATH, 'custom_options.sh'), | ||
DAEMON_BIND_HOST : process.env.PM2_BIND_ADDR || 'localhost', | ||
@@ -36,3 +42,6 @@ DAEMON_RPC_PORT : parseInt(process.env.PM2_RPC_PORT) || 6666, // RPC commands | ||
SAMPLE_FILE_PATH : '../lib/sample.json', | ||
STARTUP_SCRIPT : '../lib/scripts/pm2-init.sh', | ||
CENTOS_STARTUP_SCRIPT : '../lib/scripts/pm2-init-centos.sh', | ||
UBUNTU_STARTUP_SCRIPT : '../lib/scripts/pm2-init.sh', | ||
SUCCESS_EXIT : 0, | ||
@@ -52,1 +61,6 @@ ERROR_EXIT : 1, | ||
}; | ||
// var custom_conf = fs.readFileSync(default_conf.PM2_CONF_FILE, 'utf8') || "{}"; | ||
// util._extend(default_conf, eval(custom_conf)); | ||
module.exports = default_conf; |
178
lib/CLI.js
@@ -88,3 +88,3 @@ | ||
console.error(cst.PREFIX_MSG_ERR + 'Script already launched, add -f option to force re execution'); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -100,8 +100,52 @@ | ||
CLI.startFromJson = function(cmd) { | ||
var data = fs.readFileSync(cmd); | ||
var appConf = JSON.parse(data); | ||
/** | ||
* Use a RPC method on the json file | ||
* @param {string} action RPC Method | ||
*/ | ||
CLI.actionFromJson = function(action, file, jsonVia) { | ||
if (jsonVia == 'pipe') | ||
var appConf = JSON.parse(file); | ||
else { | ||
var data = fs.readFileSync(file); | ||
var appConf = JSON.parse(data); | ||
} | ||
if (!Array.isArray(appConf)) appConf = [appConf]; //convert to array | ||
async.eachLimit(appConf, cst.CONCURRENT_ACTIONS, function(proc, next) { | ||
var name; | ||
if (!proc.name) | ||
name = p.basename(proc.script); | ||
else | ||
name = proc.name; | ||
Satan.executeRemote(action, name, function(err, list) { | ||
if (err) | ||
console.error(err); | ||
console.log(cst.PREFIX_MSG + 'Stopping process by name ' + name); | ||
delete name; | ||
next(); | ||
}); | ||
}, function(err) { | ||
if (err) { | ||
console.log(err); | ||
return exitCli(cst.ERROR_EXIT); | ||
} | ||
return setTimeout(speedList, 800); | ||
}); | ||
}; | ||
CLI.startFromJson = function(cmd,jsonVia) { | ||
if (jsonVia == 'pipe') | ||
var appConf = JSON.parse(cmd); | ||
else { | ||
var data = fs.readFileSync(cmd); | ||
var appConf = JSON.parse(data); | ||
} | ||
if (!Array.isArray(appConf)) appConf = [appConf]; //convert to array | ||
(function ex(apps) { | ||
@@ -158,3 +202,3 @@ if (apps.length == 0) return speedList(); | ||
console.error(cst.PREFIX_MSG + 'sudo env PATH=$PATH:' + p.dirname(process.execPath) + ' pm2 startup ' + platform + ' -u ' + stdout.trim()); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
}); | ||
@@ -165,7 +209,13 @@ return; | ||
var INIT_SCRIPT = "/etc/init.d/pm2-init.sh"; | ||
var script = fs.readFileSync(path.join(__dirname, cst.STARTUP_SCRIPT)); | ||
var script; | ||
if (platform == 'centos' || platform == 'redhat') | ||
script = fs.readFileSync(path.join(__dirname, cst.CENTOS_STARTUP_SCRIPT)); | ||
else | ||
script = fs.readFileSync(path.join(__dirname, cst.UBUNTU_STARTUP_SCRIPT)); | ||
script = script.toString().replace(/%PM2_PATH%/g, process.mainModule.filename); | ||
script = script.toString().replace(/%HOME_PATH%/g, process.env.HOME); | ||
script = script.toString().replace(/%NODE_PATH%/g, process.execPath); | ||
script = script.toString().replace(/%NODE_PATH%/g, p.dirname(process.execPath)); | ||
script = script.toString().replace(/%USER%/g, commander.user || 'root'); | ||
@@ -180,3 +230,3 @@ | ||
console.log(cst.PREFIX_MSG_ERR + ' There is a problem when trying to write file : ' + INIT_SCRIPT); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -187,5 +237,8 @@ | ||
console.log(cst.PREFIX_MSG + 'Making script booting at startup...'); | ||
if (platform == 'centos') { | ||
cmd = 'chmod +x ' + INIT_SCRIPT + '; chkconfig --level 2345 ' + p.basename(INIT_SCRIPT) + ' on'; | ||
if (platform == 'centos' || platform == 'redhat') { | ||
cmd = 'chmod +x ' + INIT_SCRIPT + '; chkconfig --add ' + p.basename(INIT_SCRIPT); | ||
console.log(cst.PREFIX_MSG + '-centos- Using the command %s', cmd); | ||
fs.openSync('/var/lock/subsys/pm2-init.sh', 'w'); | ||
console.log('/var/lock/subsys/pm2-init.sh lockfile has been added'); | ||
} | ||
@@ -200,7 +253,8 @@ else { | ||
console.error(err); | ||
process.exit(cst.ERROR_EXIT); | ||
console.log('----- Are you sure you use the right platform command line option ? centos / redhat or ubuntu ?'); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
console.log(stdo); | ||
console.log(cst.PREFIX_MSG + 'Done.'); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}); | ||
@@ -215,3 +269,3 @@ }; | ||
console.log('Successfully launched interactor'); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}); | ||
@@ -225,6 +279,6 @@ }; | ||
console.error(err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
console.log('Interactor successfully killed'); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}); | ||
@@ -238,6 +292,6 @@ }); | ||
console.error(err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
console.log(res); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}); | ||
@@ -278,3 +332,3 @@ }; | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -285,3 +339,3 @@ | ||
UX.processing.stop(); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
} | ||
@@ -322,3 +376,3 @@ | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -334,3 +388,3 @@ | ||
console.error('Error : ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -366,3 +420,3 @@ console.log(cst.PREFIX_MSG + 'Process %s succesfully reloaded', proc.pm2_env.name); | ||
console.error('Error : ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -384,3 +438,3 @@ console.log(cst.PREFIX_MSG + 'Process %s succesfully reloaded', proc.pm2_env.name); | ||
console.error('Error : ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -397,3 +451,3 @@ UX.processing.stop(); | ||
console.error('Error : ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -410,3 +464,3 @@ UX.processing.stop(); | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -424,3 +478,3 @@ | ||
console.error('Error : ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -440,3 +494,3 @@ console.log(cst.PREFIX_MSG + 'Process ' + proc.pm2_env.name + ' restarted'); | ||
console.error(cst.PREFIX_MSG_ERR + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -449,3 +503,6 @@ UX.processing.stop(); | ||
CLI.deleteProcess = function(process_name) { | ||
if (process_name == 'all') { | ||
if (process_name.indexOf('.json') > 0) { | ||
return CLI.actionFromJson('deleteProcessName', process_name); | ||
} | ||
else if (process_name == 'all') { | ||
console.log(cst.PREFIX_MSG + 'Stopping and deleting all processes'); | ||
@@ -455,3 +512,3 @@ Satan.executeRemote('deleteAll', {}, function(err, list) { | ||
console.error(cst.PREFIX_MSG_ERR + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -467,3 +524,3 @@ UX.processing.stop(); | ||
console.error(cst.PREFIX_MSG_ERR + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -479,3 +536,3 @@ UX.processing.stop(); | ||
console.error('\n' + cst.PREFIX_MSG_ERR + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -492,3 +549,3 @@ UX.processing.stop(); | ||
console.error(err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -505,3 +562,3 @@ console.log(cst.PREFIX_MSG + 'Stopping process by name ' + name); | ||
console.error(cst.PREFIX_MSG_ERR + pm2_id + ' : pm2 id not found'); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -522,3 +579,3 @@ console.log(cst.PREFIX_MSG + ' Process stopped'); | ||
console.info(dt); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}; | ||
@@ -534,3 +591,3 @@ | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -541,3 +598,3 @@ if (debug) | ||
console.log(JSON.stringify(list)); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}); | ||
@@ -553,3 +610,3 @@ }; | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -564,3 +621,3 @@ list.forEach(function(l) { | ||
}); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}); | ||
@@ -576,3 +633,3 @@ }; | ||
console.error('Error : ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -592,3 +649,3 @@ console.log(cst.PREFIX_MSG + 'Succesfully sent signal %s to process name %s', signal, process_name); | ||
console.error(err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -605,7 +662,7 @@ console.log(cst.PREFIX_MSG + 'Succesfully sent signal %s to process id %s', signal, process_id); | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
if (Object.keys(list).length == 0) { | ||
console.log(cst.PREFIX_MSG + 'No online process to monitor'); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -619,3 +676,3 @@ | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -638,3 +695,3 @@ setTimeout(function() { | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -664,6 +721,6 @@ | ||
console.error('Error when killing daemon'); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
console.info('Daemon killed'); | ||
process.exit(cst.SUCCESS_EXIT); | ||
exitCli(cst.SUCCESS_EXIT); | ||
}); | ||
@@ -681,4 +738,3 @@ }; | ||
UX.processing.stop(); | ||
if (commander.silent) | ||
process.exit(cst.SUCCESS_EXIT); | ||
Satan.executeRemote('getMonitorData', {}, function(err, list) { | ||
@@ -691,12 +747,26 @@ if (err) { | ||
console.error('Error retrieving process list: %s.\nA process seems to be on infinite loop, retry in 5 seconds',err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
if (commander.miniList) | ||
if (commander.miniList && !commander.silent) | ||
UX.miniDisplay(list); | ||
else | ||
else if (!commander.silent) | ||
UX.dispAsTable(list); | ||
return process.exit(cst.SUCCESS_EXIT); | ||
if (commander.daemon) { | ||
return exitCli(cst.SUCCESS_EXIT); | ||
} | ||
else { | ||
console.log('--no-daemon option enabled = do not exit pm2 CLI'); | ||
console.log('PM2 dameon PID = %s', fs.readFileSync(cst.PM2_PID_FILE_PATH)); | ||
return Log.stream(cst.PM2_LOG_FILE_PATH); | ||
} | ||
}); | ||
} | ||
function exitCli(code) { | ||
Satan.client.sock.close(); | ||
return process.exit(code); | ||
} | ||
function resolvePaths(appConf) { | ||
@@ -706,3 +776,3 @@ var app = Common.resolveAppPaths(appConf, null, console.log); | ||
console.error(cst.PREFIX_MSG_ERR + app.message); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -718,3 +788,3 @@ return app; | ||
console.error('Error retrieving process list: ' + err); | ||
process.exit(cst.ERROR_EXIT); | ||
exitCli(cst.ERROR_EXIT); | ||
} | ||
@@ -721,0 +791,0 @@ |
@@ -21,2 +21,4 @@ | ||
console.log('status : %s', status); | ||
console.log('mode : %s', mode); | ||
console.log('port : %s', port); | ||
console.log('restarted : %d', l.pm2_env.restart_time ? l.pm2_env.restart_time : 0); | ||
@@ -23,0 +25,0 @@ console.log('uptime : %s', (l.pm2_env.pm_uptime && status == 'online') ? timeSince(l.pm2_env.pm_uptime) : 0); |
@@ -62,3 +62,4 @@ 'use strict'; | ||
total: os.totalmem() | ||
} | ||
}, | ||
time: Date.now() | ||
}, | ||
@@ -321,2 +322,3 @@ processes: processes | ||
God.deleteAll({}, function() { | ||
console.log('pm2 has been killed by command line'); | ||
God.bus.emit('pm2:kill', { | ||
@@ -323,0 +325,0 @@ status : 'killed', |
@@ -115,3 +115,8 @@ 'use strict'; | ||
}); | ||
old_worker.disconnect(); | ||
try { | ||
old_worker.disconnect(); | ||
} catch(e) { | ||
console.error('Worker %d is already disconnected', old_worker.pm2_env.pm_id); | ||
God.deleteProcessId(t_key, cb); | ||
} | ||
}); | ||
@@ -118,0 +123,0 @@ return false; |
@@ -14,2 +14,9 @@ // | ||
// Start daemon | ||
// | ||
// Usually it would be is started in the parent process already, | ||
// but if I run "node HttpInterface" directly, I would probably | ||
// like it to be not daemonized | ||
Satan.start(true); | ||
http.createServer(function (req, res) { | ||
@@ -16,0 +23,0 @@ // Add CORS headers to allow browsers to fetch data directly |
@@ -10,3 +10,3 @@ // ProcessContainer.js | ||
require('coffee-script'); | ||
require('coffee-script/register'); | ||
@@ -95,5 +95,3 @@ /** | ||
process.on('uncaughtException', function(err) { | ||
stderr.write(err.stack); | ||
process.on('uncaughtException', function uncaughtListener(err) { | ||
// Notify master that an uncaughtException has been catched | ||
@@ -111,3 +109,8 @@ process.send({ | ||
process.exit(cst.CODE_UNCAUGHTEXCEPTION); | ||
if (!process.listeners('uncaughtException').filter(function (listener) { | ||
return listener !== uncaughtListener; | ||
}).length) { | ||
stderr.write(err.stack); | ||
process.exit(cst.CODE_UNCAUGHTEXCEPTION); | ||
} | ||
}); | ||
@@ -114,0 +117,0 @@ |
@@ -32,33 +32,25 @@ 'use strict'; | ||
/** | ||
* Code switcher | ||
* It will switch between Daemon part and Client part | ||
* This function ensures that daemon is running and start it if it doesn't | ||
* | ||
* This method is called at the end of this file. | ||
* @api public | ||
*/ | ||
Satan.start = function(noDaemonMode) { | ||
Satan.pingDaemon(function(ab) { | ||
// If Daemon not alive | ||
if (ab == false) { | ||
if (noDaemonMode) { | ||
return Satan.remoteWrapper(); | ||
} | ||
Satan.onReady = function() { | ||
(function init() { | ||
if (process.env.DAEMON) { | ||
// DAEMON Only used for differenciating the daemon of the client | ||
delete process.env.DAEMON; | ||
process.title = 'pm2: Satan Daemonizer'; | ||
Satan.remoteWrapper(); | ||
} | ||
else { | ||
Satan.pingDaemon(function(ab) { | ||
// If Daemon not alive | ||
if (ab == false) { | ||
// Daemonize | ||
return Satan.launchDaemon(function(err, child) { | ||
if (err) { | ||
console.error(err); | ||
process.exit(cst.ERROR_EXIT); | ||
} | ||
Satan.launchRPC(); | ||
}); | ||
// Daemonize | ||
return Satan.launchDaemon(function(err, child) { | ||
if (err) { | ||
console.error(err); | ||
process.exit(cst.ERROR_EXIT); | ||
} | ||
return Satan.launchRPC(); | ||
Satan.launchRPC(); | ||
}); | ||
} | ||
})(); | ||
return Satan.launchRPC(); | ||
}); | ||
}; | ||
@@ -71,4 +63,21 @@ | ||
*/ | ||
Satan.processStateHandler = function() { | ||
function gracefullExit() { | ||
console.log('pm2 has been killed by signal'); | ||
try { | ||
fs.unlinkSync(cst.PM2_PID_FILE_PATH); | ||
} catch(e){} | ||
process.exit(0); | ||
} | ||
try { | ||
fs.writeFileSync(cst.PM2_PID_FILE_PATH, process.pid); | ||
} catch(e){} | ||
process.on('SIGTERM', gracefullExit); | ||
process.on('SIGINT', gracefullExit); | ||
process.on('SIGQUIT', gracefullExit); | ||
}; | ||
Satan.remoteWrapper = function() { | ||
Satan.processStateHandler(); | ||
@@ -94,5 +103,7 @@ if (process.env.SILENT == 'true') { | ||
// Send ready message to Satan Client | ||
process.send({ | ||
online : true, success : true, pid : process.pid | ||
}); | ||
if (typeof(process.send) === 'function') { | ||
process.send({ | ||
online : true, success : true, pid : process.pid | ||
}); | ||
} | ||
@@ -176,3 +187,2 @@ /** | ||
env : util._extend({ | ||
'DAEMON' : true, | ||
'SILENT' : cst.DEBUG ? !cst.DEBUG : true, | ||
@@ -232,3 +242,2 @@ 'HOME' : process.env.HOME | ||
debug('Connected to Daemon'); | ||
process.emit('satan:client:ready'); | ||
@@ -250,7 +259,9 @@ }); | ||
/** | ||
* Call the method once every methods | ||
* has been taken into account | ||
*/ | ||
Satan.onReady(); | ||
// | ||
// If this file is a main process, it means that | ||
// this process is being forked by pm2 itself | ||
// | ||
if (require.main === module) { | ||
process.title = 'pm2: Satan Daemonizer'; | ||
Satan.remoteWrapper(); | ||
} |
{ | ||
"name": "pm2", | ||
"preferGlobal": "true", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"engines" : { | ||
@@ -39,3 +39,3 @@ "node" : ">=0.8" | ||
"scripts": { | ||
"test": "bash ./test/cli.sh && bash ./test/reload.sh && bash ./test/gracefulReload.sh && bash ./test/cli2.sh && bash ./test/misc.sh && bash ./test/fork.sh && bash ./test/infinite_loop.sh && NODE_ENV=test ./node_modules/mocha/bin/mocha test" | ||
"test": "bash ./test/cli.sh && bash ./test/json_file.sh && bash ./test/harmony.sh && bash ./test/reload.sh && bash ./test/gracefulReload.sh && bash ./test/cli2.sh && bash ./test/misc.sh && bash ./test/fork.sh && bash ./test/infinite_loop.sh && NODE_ENV=test ./node_modules/mocha/bin/mocha test" | ||
}, | ||
@@ -48,2 +48,3 @@ "keywords": [ | ||
"pm2", | ||
"harmony", | ||
"node-pm2", | ||
@@ -76,3 +77,3 @@ "monitoring", | ||
"colors" : "0.6.2", | ||
"coffee-script" : "*", | ||
"coffee-script" : "1.7.0", | ||
"eventemitter2" : "0.4.13", | ||
@@ -91,3 +92,3 @@ "debug" : "*", | ||
}, | ||
"license": "Apache v2" | ||
"license": "AGPLv3" | ||
} |
112
README.md
@@ -14,3 +14,3 @@ # ![Monit](https://github.com/unitech/pm2/raw/master/pres/top-logo-wo.png) | ||
- 0s downtime reload for Node | ||
- Startup scripts for Ubuntu and CentOS | ||
- Startup scripts for Ubuntu/CentOS (use updaterc.d for Ubuntu and chkconfig for others) | ||
- Stop unstable process (avoid infinite loop) | ||
@@ -51,4 +51,21 @@ - Monitoring in console | ||
- 0.7.2 | ||
- harmony can be enabled [Enabling harmony](#a66) | ||
- can pass any options to node via PM2_NODE_OPTIONS, configurable via ~/.pm2/custom_options.sh | ||
- pid file written in ~/.pm2/pm2.pid | ||
- startup script support for CentOS | ||
- --no-daemon option (Alex Kocharin) | ||
- json file now can be : started/stoped/restarted/deleted | ||
- coffeescript support for new versions (Hao-kang Den) | ||
- accept JSON via pipe from standard input (Ville Walveranta) | ||
- adjusting logical when process got an uncaughtException (Ethanz) | ||
- 0.7.1 integrates hardened reload, graceful reload and strengthened process management | ||
# Updates | ||
## Update from 0.x -> 0.7.2 | ||
- CentOS crontab option should not be used anymore and use the new init script with `pm2 startup centos` | ||
- If you use the configuration file or the harmonoy option, you should regenerate the init script | ||
# Readme Contents | ||
@@ -62,2 +79,3 @@ | ||
- [CoffeeScript](#a19) | ||
- [Enabling Harmony](#a66) | ||
- [Is my production server ready for PM2](#a4) | ||
@@ -96,2 +114,4 @@ - [Listing processes : pm2 list](#a6) | ||
$ pm2 start app.js --no-daemon # Doesn't exit process | ||
$ pm2 list # Display all processes status | ||
@@ -116,3 +136,4 @@ $ pm2 list -m # Serious display | ||
$ pm2 startup # Generate init script to keep processes alive | ||
$ pm2 startup ubuntu # Generate init script for ubuntu to keep processes alive on restart | ||
# ubuntu/centos | ||
@@ -175,5 +196,7 @@ $ pm2 web # Launch Health computer API endpoint (http://localhost:9615) | ||
├── dump.pm2 | ||
├── custom_options.sh | ||
├── pm2.log | ||
├── pm2.pid | ||
├── logs | ||
├── pids | ||
└── pm2.log | ||
└── pids | ||
``` | ||
@@ -237,2 +260,27 @@ | ||
<a name="a66"/> | ||
## Enabling Harmony ES6 | ||
You can enable Harmony ES6 by setting `PM2_NODE_OPTIONS='--harmony'` environment variable option when you start pm2 (pm2 should not be already daemonized). | ||
To pass this option by default, you can edit `~/.pm2/custom_options.sh` and add : | ||
```bash | ||
export PM2_NODE_OPTIONS='--harmony' | ||
``` | ||
Then : | ||
```bash | ||
$ pm2 dump | ||
$ pm2 exit | ||
$ pm2 resurrect | ||
``` | ||
If ES6 has been enabled you should see this message at the beggining of each pm2 commands : | ||
``` | ||
● ES6 mode | ||
``` | ||
<a name="a23"/> | ||
@@ -304,13 +352,17 @@ ## Fork mode - execute script in different languages | ||
<a name="a8"/> | ||
## pm2 automatic startup script generation | ||
## Startup script generation : pm2 startup | ||
PM2 provides an automatic way to keep Node processes alive on server restart. | ||
On exit it will dump the process list and their environment and will resurrect them on startup. | ||
It uses **System V init script** compatible with **Ubuntu and CentOS** (maybe it works on other sys but not 100% sure). | ||
It uses **System V init script** compatible with **Ubuntu/CentOS/Redhat** (maybe it works on other sys but not 100% sure). | ||
```bash | ||
$ pm2 startup # then follow the command instruction | ||
$ pm2 startup centos # will try to use chkconfig instead of updaterc.d | ||
$ pm2 startup ubuntu # then follow the command instruction | ||
$ pm2 startup centos # will use chkconfig instead of updaterc.d | ||
$ pm2 startup redhat # not very stable for redhat | ||
``` | ||
Init script generated are located in /etc/init.d/pm2-init.sh. | ||
### Running script as a different user | ||
@@ -342,6 +394,8 @@ | ||
<a name="a24"/> | ||
## Customization | ||
## Configuration / Customization | ||
Multiple variables can be customized via the environment : | ||
You can edit these options by editing the file `~/.pm2/custom_options.sh` | ||
These variables can be customized : | ||
``` | ||
@@ -354,5 +408,8 @@ DAEMON_BIND_HOST : process.env.PM2_BIND_ADDR || 'localhost', | ||
GRACEFUL_TIMEOUT : parseInt(process.env.PM2_GRACEFUL_TIMEOUT) || 4000, | ||
PM2_NODE_OPTIONS : '' | ||
``` | ||
<a name="a13"/> | ||
@@ -393,2 +450,5 @@ # Multi process JSON declaration | ||
$ pm2 start processes.json | ||
$ pm2 stop processes.json | ||
$ pm2 delete processes.json | ||
$ pm2 restart processes.json | ||
``` | ||
@@ -401,3 +461,3 @@ | ||
``` | ||
```bash | ||
$ pm2 kill # kill the current pm2 | ||
@@ -413,2 +473,13 @@ $ git clone my_pm2_fork.git | ||
## Install pm2 development | ||
```bash | ||
$ npm install git://github.com/Unitech/pm2#development -g | ||
``` | ||
# MISC Notes | ||
- Remove init script : `sudo update-rc.d -f pm2-init.sh remove` | ||
<a name="a21"/> | ||
@@ -490,16 +561,5 @@ # Known bugs and workarounds | ||
<a name="a15"/> | ||
# License - Apache License v2 | ||
# License | ||
Copyright [2013] [Strzelewicz Alexandre <as@unitech.io>] | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
Files in lib/ are made available under the terms of the GNU Affero General Public License (AGPL). | ||
pm2-interface is made under the terms of the Apache V2 license. |
# Installing development version | ||
```bash | ||
$ npm install git://github.com/Unitech/pm2.git#development -g | ||
``` | ||
# Redhat | ||
``` | ||
$ sudo yum install git wget emacs | ||
$ sudo yum groupinstall "Development Tools" | ||
$ wget -qO- https://raw.github.com/creationix/nvm/master/install.sh | sh | ||
$ # put .bash_profile content to .bashrc | ||
$ source .bashrc | ||
$ nvm install v0.11.10 | ||
$ nvm alias default 0.11.10 | ||
$ npm install pm2 -g | ||
$ # OR | ||
$ npm install git://github.com/Unitech/pm2.git#development -g | ||
``` | ||
# CentOS | ||
@@ -10,5 +31,11 @@ | ||
## Remove init script | ||
``` | ||
$ chkconfig --del pm2-init.sh | ||
$ chkconfig --add pm2-init.sh | ||
``` | ||
gyp WARN EACCES user "root" does not have permission to create dev dir : | ||
https://github.com/TooTallNate/node-gyp/issues/126 | ||
-> add --unsafe-perm |
@@ -17,2 +17,3 @@ | ||
Satan = require('../lib/Satan'); | ||
Satan.start(); | ||
process.once('satan:client:ready', function() { | ||
@@ -40,3 +41,3 @@ console.log('Client ready'); | ||
Satan.should.have.property('remoteWrapper'); | ||
Satan.should.have.property('onReady'); | ||
Satan.should.have.property('start'); | ||
Satan.should.have.property('launchRPC'); | ||
@@ -88,5 +89,5 @@ Satan.should.have.property('executeRemote'); | ||
}, function(err, procs) { | ||
assert(err == null); | ||
assert(err == null); | ||
assert(procs.length == 4); | ||
done(); | ||
done(); | ||
}); | ||
@@ -93,0 +94,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
664120
121
3703
1
552
2
70
+ Addedcoffee-script@1.7.0(transitive)
+ Addedmkdirp@0.3.5(transitive)
- Removedcoffee-script@1.12.7(transitive)
Updatedcoffee-script@1.7.0