Comparing version 2.9.3 to 2.10.0
151
CHANGELOG.md
@@ -0,2 +1,153 @@ | ||
## v2.10.0 ( Mon Feb 19 2018 14:51:19 GMT+0100 (CET) ) | ||
### Bug Fixes | ||
- add livescript in default modules | ||
([a315eeb6](https://github.com/Unitech/pm2/commit/a315eeb65f04b22643a903f0cb1c0f416615ad8b)) | ||
- replace dash with underscore | ||
([203df768](https://github.com/Unitech/pm2/commit/203df7688ca348967c00bc45289ae70fd2c4aaaa)) | ||
- make sure not pm2 is running | ||
([bd798fd7](https://github.com/Unitech/pm2/commit/bd798fd748665e935db4bb91f9d1d66952d9842a)) | ||
- auto-exit edge case fix + pm2 no daemon mode + log in raw by default + less logs | ||
([704ae518](https://github.com/Unitech/pm2/commit/704ae518f5d7df0a631349e518d81cef51249a58)) | ||
- impact v8 flag in fork mode also | ||
([41bf6ef7](https://github.com/Unitech/pm2/commit/41bf6ef7d3633180b4c1e90f36eb206d82fab2b1)) | ||
- fixup! #2182 Get rid of annoying popups in Windows 10 | ||
([3a85b59d](https://github.com/Unitech/pm2/commit/3a85b59de4a76796ad0880368d8d085a7ba55d36)) | ||
### Hot Fixes | ||
- \#3420 ([673acf36](https://github.com/Unitech/pm2/commit/673acf36b4ca1fd65c5135a92d56081f76237a8b)) | ||
### Features | ||
- add dependencies section into ecosystem.json file. | ||
([828a30d0](https://github.com/Unitech/pm2/commit/828a30d0ccc88b3f6e2b66d517ccf5f2394bd08b)) | ||
- --deep-monitoring available from pm2-runtime | ||
([99e62e3b](https://github.com/Unitech/pm2/commit/99e62e3bb808f071d6e4850c234b34f7de65b1c2)) | ||
- add deep_metrics to deep_monitoring flag | ||
([4d1bea5e](https://github.com/Unitech/pm2/commit/4d1bea5e0bbaab1f16f75d012bca25702cdff88e)) | ||
- add flag to enable deep-monitoring | ||
([c5418688](https://github.com/Unitech/pm2/commit/c541868837a1c4421394de5dd1029d2619b5ac82)) | ||
- allow pm2 to install a set of module as one single command and add deep-monitoring. | ||
([9dddc80d](https://github.com/Unitech/pm2/commit/9dddc80db5e496def44d4d36716b7de54e5171cf)) | ||
- pm2 pid <app_name> command | ||
([6687d499](https://github.com/Unitech/pm2/commit/6687d499415151bd62489fed5331f414576ec354)) | ||
- allow pm2 to install and enable event-loop-inspector data collecting | ||
([e6b0c474](https://github.com/Unitech/pm2/commit/e6b0c47443d3e6a839bf29057ef0a80ef135c47e)) | ||
- ignore signal when running in --no-daemon | ||
([b9c01c99](https://github.com/Unitech/pm2/commit/b9c01c99d54aba98ab790b8888500ac0f0af05c9)) | ||
- upgrade pmx to git development branch | ||
([21be05a0](https://github.com/Unitech/pm2/commit/21be05a07bd93eacaddedde3b647c16468937473)) | ||
- allow pm2 to enable v8 data collecting from pmx | ||
([aa180fa8](https://github.com/Unitech/pm2/commit/aa180fa8ab47f0c687d7c21854d005ad0ebf8475)) | ||
- allow pm2 to install gc-stats | ||
([15634168](https://github.com/Unitech/pm2/commit/15634168582e4c7b3c5f47a3f58a0fcf8b732a76)) | ||
- feat add changelog generation support | ||
([14f53fc0](https://github.com/Unitech/pm2/commit/14f53fc0c28be4084778785aeace3763ed0d827f)) | ||
- **pm2** | ||
- add pm2 init option to generate an ecosystem file | ||
([5d56fac7](https://github.com/Unitech/pm2/commit/5d56fac7cc12590af29ee46c68ba32a82a2b813b)) | ||
- add pm2 init option to generate an ecosystem file | ||
([a38fd199](https://github.com/Unitech/pm2/commit/a38fd199b90d27a2405f8cabab0e4f6e45c69b08)) | ||
### Documentation | ||
- add documentation on new pm2 install command | ||
([c90c453f](https://github.com/Unitech/pm2/commit/c90c453f85b07adb346bc55c2b685d689a2e96f7)) | ||
- add sendDataToProcessId into typescript definitions | ||
([4a2e8d2d](https://github.com/Unitech/pm2/commit/4a2e8d2d2c4b38fe0ff2377dfe32fce9a43c8044)) | ||
### Refactor | ||
- delete all "if" condition when installing new module, create an object with all modules and a generic installation process | ||
([1b92a9c4](https://github.com/Unitech/pm2/commit/1b92a9c4000734367e68d8dbd60d0901009f4c56)) | ||
- deep pm2-runtime refactor #3408 #3257 #3266 | ||
([c13b2364](https://github.com/Unitech/pm2/commit/c13b23648269529a1f998d816be10f895665861e)) | ||
- no more interactive spinner for connection to KM + change pm2 log format + remove some logs | ||
([d1916f40](https://github.com/Unitech/pm2/commit/d1916f40962b2cc8a1866172eab7d5d89db093be)) | ||
### Chore | ||
- pmx to 1.6.3-rc2 | ||
([41815e0b](https://github.com/Unitech/pm2/commit/41815e0ba0298979f936b3d4badb196f8d9783d8)) | ||
- switch pmx to development | ||
([748019d1](https://github.com/Unitech/pm2/commit/748019d1ef0cf760b5e8de9d5b6af6fee300db02)) | ||
- 2.10.0-beta | ||
([0d2b7172](https://github.com/Unitech/pm2/commit/0d2b7172a093d0638deabb5f23383cc9eec5dda9)) | ||
- upgrade pmx to 1.6.3-next | ||
([5a1b4343](https://github.com/Unitech/pm2/commit/5a1b4343cc1e1f5018e21451a111340351706213)) | ||
- upgrade pmx dep | ||
([4bbeec3d](https://github.com/Unitech/pm2/commit/4bbeec3d170ba63af0c0ae0e2d07beec2ab49772)) | ||
- switch to published pmx(@next) | ||
([859d18fb](https://github.com/Unitech/pm2/commit/859d18fbc79e2a2760fe90e9c17e71209f8177ce)) | ||
- remove --exit from mocha.opts | ||
([36bf03e1](https://github.com/Unitech/pm2/commit/36bf03e1eed69a27e518151e2f7aa958b15db2fb)) | ||
- remove unused files | ||
([65d233e5](https://github.com/Unitech/pm2/commit/65d233e5b5290f65796b7cf3daa20706e0f3bee6)) | ||
### Branchs merged | ||
- Merge branch 'development' of ssh://github.com/deltasource/pm2 into hotfix/scoped-package-support | ||
([94ea9d9e](https://github.com/Unitech/pm2/commit/94ea9d9eeff40faca8aa9f7edfc81aa29c08e740)) | ||
- Merge branch 'master' into development | ||
([46606903](https://github.com/Unitech/pm2/commit/46606903f25d0f4d0eee226da863e20e4b396dc9)) | ||
- Merge branch 'development' of github.com:Unitech/pm2 into v8_option | ||
([757562f7](https://github.com/Unitech/pm2/commit/757562f755b09124bbd006209ae38a096d692529)) | ||
- Merge branch 'development' of github.com:Unitech/pm2 into gc-stats | ||
([3ed1a747](https://github.com/Unitech/pm2/commit/3ed1a7471aec7d79f7d604447ac7445720bdaced)) | ||
- Merge branch 'master' into development | ||
([ee7651e4](https://github.com/Unitech/pm2/commit/ee7651e47e944c3c829933494c6cc765deb4bb29)) | ||
### Pull requests merged | ||
- Merge pull request #3466 from natcl/development | ||
([c6d7ace8](https://github.com/Unitech/pm2/commit/c6d7ace802e667def75bc68344effa4856830fb4)) | ||
- Merge pull request #3464 from andyfleming/patch-1 | ||
([dd9ebb60](https://github.com/Unitech/pm2/commit/dd9ebb6051708ee5a13cc68dbcb8238e41860bb9)) | ||
- Merge pull request #3459 from rmonnier/master | ||
([46948a98](https://github.com/Unitech/pm2/commit/46948a98e90c7864f7b8100db5c519fe9d37f11a)) | ||
- Merge pull request #3458 from Unitech/pm2_install_command | ||
([f3b35726](https://github.com/Unitech/pm2/commit/f3b35726895bd82b92813f308b787d68e9df1fa4)) | ||
- Merge pull request #3453 from deltasource/hotfix/scoped-package-support | ||
([974f9bf0](https://github.com/Unitech/pm2/commit/974f9bf0dc7a7aa7ff6860f8640da3593b802296)) | ||
- Merge pull request #3448 from Unitech/deep_monitoring_flag | ||
([331bc741](https://github.com/Unitech/pm2/commit/331bc741d7285094738a91cd816bc9755cc76605)) | ||
- Merge pull request #3447 from Unitech/deep-monitoring | ||
([719d328e](https://github.com/Unitech/pm2/commit/719d328e8d14871b34fd33df54fd80f4f8e7825f)) | ||
- Merge pull request #3443 from Unitech/event-loop-inspector | ||
([77a35274](https://github.com/Unitech/pm2/commit/77a3527407f3d090c7a5fa0bedaf943a7536b5eb)) | ||
- Merge pull request #3442 from Unitech/event-loop-inspector | ||
([dad98e6e](https://github.com/Unitech/pm2/commit/dad98e6e0738983717fee155ff0f6519955ffc1b)) | ||
- Merge pull request #3424 from Unitech/sendDataToProcessId_def | ||
([95e85eef](https://github.com/Unitech/pm2/commit/95e85eef84510dddfb0c6b13f0ada38a7dd66cae)) | ||
- Merge pull request #3438 from Unitech/v8_option | ||
([e46b15dc](https://github.com/Unitech/pm2/commit/e46b15dc32c18e8b24f66da0c79cc06f91cf11b5)) | ||
- Merge pull request #3437 from Unitech/gc-stats | ||
([1a6771aa](https://github.com/Unitech/pm2/commit/1a6771aa361bb5718bafd6e33e616725f9c0d328)) | ||
- Merge pull request #3400 from toddwong/windowsHide2 | ||
([f65e8794](https://github.com/Unitech/pm2/commit/f65e8794df6e67f4ff60dfbec7c05a37721cb6f9)) | ||
- Merge pull request #3421 from Unitech/generate_changelog | ||
([b0690618](https://github.com/Unitech/pm2/commit/b0690618d940c11e28eeb5115c060bf363c7b62b)) | ||
- Merge pull request #3419 from Rohja/fix-build-number-deb-rpm | ||
([b4343de2](https://github.com/Unitech/pm2/commit/b4343de2703fce03f3cf48cc303b12bc6b69b743)) | ||
## 2.9.2 | ||
@@ -3,0 +154,0 @@ |
@@ -31,2 +31,3 @@ /** | ||
APP_CONF_DEFAULT_FILE : 'ecosystem.json', | ||
APP_CONF_TPL : 'ecosystem.tpl', | ||
@@ -33,0 +34,0 @@ APP_CONF_TPL_SIMPLE : 'ecosystem-simple.tpl', |
@@ -46,2 +46,25 @@ # Contributing | ||
## Commit rules | ||
### Commit message | ||
A good commit message should describe what changed and why. | ||
It should : | ||
* contain a short description of the change (preferably 50 characters or less) | ||
* be entirely in lowercase with the exception of proper nouns, acronyms, and the words that refer to code, like function/variable names | ||
* be prefixed with one of the following word | ||
* fix : bug fix | ||
* hotfix : urgent bug fix | ||
* feat : new or updated feature | ||
* docs : documentation updates | ||
* BREAKING : if commit is a breaking change | ||
* refactor : code refactoring (no functional change) | ||
* perf : performance improvement | ||
* style : UX and display updates | ||
* test : tests and CI updates | ||
* chore : updates on build, tools, configuration ... | ||
* Merge branch : when merging branch | ||
* Merge pull request : when merging PR | ||
## Tests | ||
@@ -48,0 +71,0 @@ |
@@ -671,2 +671,6 @@ /** | ||
// Options set via environment variables | ||
if (process.env.PM2_DEEP_MONITORING) | ||
app_conf.deep_monitoring = true; | ||
if (typeof app_conf.name == 'function'){ | ||
@@ -1454,2 +1458,6 @@ delete app_conf.name; | ||
// Options set via environment variables | ||
if (process.env.PM2_DEEP_MONITORING) | ||
appConf.deep_monitoring = true; | ||
// Force deletion of defaults values set by commander | ||
@@ -1456,0 +1464,0 @@ // to avoid overriding specified configuration by user |
@@ -120,2 +120,30 @@ | ||
CLI.prototype.getPID = function(app_name, cb) { | ||
var that = this; | ||
if (typeof(app_name) === 'function') { | ||
cb = app_name; | ||
app_name = null; | ||
} | ||
this.Client.executeRemote('getMonitorData', {}, function(err, list) { | ||
if (err) { | ||
Common.printError(cst.PREFIX_MSG_ERR + err); | ||
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT); | ||
} | ||
var pids = []; | ||
list.forEach(function(app) { | ||
if (!app_name || app_name == app.name) | ||
pids.push(app.pid); | ||
}) | ||
if (!cb) { | ||
Common.printOut(pids.join("\n")) | ||
return that.exitCli(cst.SUCCESS_EXIT); | ||
} | ||
return cb(null, pids); | ||
}) | ||
} | ||
/** | ||
@@ -122,0 +150,0 @@ * Create PM2 memory snapshot |
@@ -197,3 +197,3 @@ /** | ||
Log.jsonStream = function(Client, app_name) { | ||
Log.jsonStream = function(Client, id) { | ||
var that = this; | ||
@@ -205,3 +205,3 @@ | ||
bus.on('process:event', function(packet) { | ||
console.log(JSON.stringify({ | ||
process.stdout.write(JSON.stringify({ | ||
timestamp : moment(packet.at), | ||
@@ -212,11 +212,18 @@ type : 'process_event', | ||
})); | ||
process.stdout.write('\n'); | ||
}); | ||
bus.on('log:*', function(type, packet) { | ||
if (app_name != 'all' && app_name && app_name != packet.process.name) return false; | ||
if (id !== 'all' | ||
&& packet.process.name != id | ||
&& packet.process.pm_id != id) | ||
return; | ||
if (type === 'PM2') | ||
return; | ||
if (typeof(packet.data) == 'string') | ||
packet.data = packet.data.replace(/(\r\n|\n|\r)/gm,''); | ||
console.log(JSON.stringify({ | ||
process.stdout.write(JSON.stringify({ | ||
message : packet.data, | ||
@@ -228,2 +235,3 @@ timestamp : moment(packet.at), | ||
})); | ||
process.stdout.write('\n'); | ||
}); | ||
@@ -230,0 +238,0 @@ }); |
@@ -24,2 +24,16 @@ /** | ||
var KNOWN_MODULES = { | ||
'deep-monitoring': { | ||
dependencies: [{name: 'v8-profiler-node8'}, {name: 'gc-stats'}, {name: 'event-loop-inspector'}] | ||
}, | ||
'gc-stats': {name: 'gc-stats'}, | ||
'event-loop-inspector': {name: 'event-loop-inspector'}, | ||
'v8-profiler': {name: 'v8-profiler-node8'}, | ||
'profiler': {name: 'v8-profiler-node8'}, | ||
'typescript': {dependencies: [{name: 'typescript'}, {name: 'ts-node@latest'}]}, | ||
'livescript': {name: 'livescript'}, | ||
'coffee-script': {name: 'coffee-script', message: 'Coffeescript v1 support'}, | ||
'coffeescript': {name: 'coffeescript', message: 'Coffeescript v2 support'} | ||
}; | ||
/** | ||
@@ -36,52 +50,46 @@ * PM2 Module System. | ||
*/ | ||
Modularizer.install = function(CLI, module_name, opts, cb) { | ||
Common.printOut(cst.PREFIX_MSG_MOD + 'Installing module ' + module_name); | ||
Modularizer.install = function (CLI, moduleName, opts, cb) { | ||
// if user want to install module from ecosystem.json file | ||
// it can also be a custom json file's name | ||
if (!moduleName || moduleName.length === 0 || moduleName.indexOf('.json') > 0) { | ||
var file = moduleName || cst.APP_CONF_DEFAULT_FILE; | ||
var isAbsolute = require('../../tools/IsAbsolute.js')(file); | ||
var filePath = isAbsolute ? file : path.join(CLI.cwd, file); | ||
var canonic_module_name = Utility.getCanonicModuleName(module_name); | ||
try { | ||
var data = fs.readFileSync(filePath); | ||
} catch (e) { | ||
Common.printError(cst.PREFIX_MSG_ERR + 'File ' + file + ' not found'); | ||
return cb(Common.retErr(e)); | ||
} | ||
if (module_name == 'v8-profiler' || module_name == 'profiler') { | ||
installLangModule('v8-profiler-node8', function(err) { | ||
if (err) { | ||
Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green('Profiling installation has FAILED (checkout previous logs)')); | ||
return cb(err); | ||
} | ||
try { | ||
var config = Common.parseConfig(data, file); | ||
} catch (e) { | ||
Common.printError(cst.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); | ||
console.error(e); | ||
return cb(Common.retErr(e)); | ||
} | ||
Common.printOut(cst.PREFIX_MSG + chalk.bold.green('V8 profiling ENABLED')); | ||
return cb(); | ||
}); | ||
return false; | ||
Modularizer.installMultipleModules(config.dependencies, cb); | ||
return; | ||
} | ||
if (module_name.indexOf('typescript') > -1) { | ||
// Special dependency install | ||
return installLangModule(module_name, function(e) { | ||
installLangModule('ts-node@latest', function(e) { | ||
Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Typescript support enabled')); | ||
return cb(e); | ||
}); | ||
}); | ||
} | ||
Common.printOut(cst.PREFIX_MSG_MOD + 'Installing module ' + moduleName); | ||
if (module_name == 'livescript') { | ||
return installLangModule('livescript', function(e) { | ||
Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Livescript support enabled')); | ||
return cb(e); | ||
}); | ||
} | ||
var canonicModuleName = Utility.getCanonicModuleName(moduleName); | ||
if (module_name.indexOf('coffee-script') > -1) { | ||
return installLangModule(module_name, function(e) { | ||
Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Coffeescript v1 support enabled')); | ||
return cb(e); | ||
}); | ||
} | ||
if (KNOWN_MODULES.hasOwnProperty(moduleName)) { | ||
var currentModule = KNOWN_MODULES[moduleName]; | ||
if (module_name.indexOf('coffeescript') > -1) { | ||
return installLangModule(module_name, function(e) { | ||
Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Coffeescript v2 support enabled')); | ||
return cb(e); | ||
}); | ||
if (currentModule && currentModule.hasOwnProperty('dependencies')) { | ||
Modularizer.installMultipleModules(currentModule.dependencies, cb); | ||
} else { | ||
installModuleByName(currentModule, cb); | ||
} | ||
return false; | ||
} | ||
moduleExist(CLI, canonic_module_name, function(exists) { | ||
moduleExist(CLI, canonicModuleName, function (exists) { | ||
if (exists) { | ||
@@ -92,9 +100,9 @@ // Update | ||
// Create a backup | ||
Rollback.backup(module_name); | ||
Rollback.backup(moduleName); | ||
return uninstallModule(CLI, { | ||
module_name : canonic_module_name, | ||
deep_uninstall : false | ||
}, function(err) { | ||
return Modularizer.installModule(CLI, module_name, opts, cb); | ||
module_name: canonicModuleName, | ||
deep_uninstall: false | ||
}, function () { | ||
return Modularizer.installModule(CLI, moduleName, opts, cb); | ||
}); | ||
@@ -104,6 +112,38 @@ } | ||
// Install | ||
Modularizer.installModule(CLI, module_name, opts, cb); | ||
}) | ||
Modularizer.installModule(CLI, moduleName, opts, cb); | ||
}); | ||
}; | ||
Modularizer.installMultipleModules = function (modules, cb) { | ||
var functionList = []; | ||
for (var i = 0; i < modules.length; i++) { | ||
functionList.push((function (index) { | ||
return function (callback) { | ||
var module = modules[index]; | ||
if (typeof modules[index] === 'string') { | ||
module = {name: modules[index]}; | ||
} | ||
installModuleByName(module, function (err) { | ||
callback(null, {module: module, err: err}); | ||
}, false); | ||
}; | ||
})(i)); | ||
} | ||
async.parallel(functionList, function (err, results) { | ||
for (var i = 0; i < results.length; i++) { | ||
var display = results[i].module.message || results[i].module.name; | ||
if (results[i].err) { | ||
err = results[i].err; | ||
Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)')); | ||
} else { | ||
Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED')); | ||
} | ||
} | ||
cb(err); | ||
}); | ||
}; | ||
Modularizer.installModule = function(CLI, module_name, opts, cb) { | ||
@@ -550,2 +590,23 @@ var proc_path = '', | ||
function installModuleByName (module, cb, verbose) { | ||
if (!module || !module.name || module.name.length === 0) { | ||
return cb(new Error('No module name !')); | ||
} | ||
if (typeof verbose === 'undefined') { | ||
verbose = true; | ||
} | ||
installLangModule(module.name, function (err) { | ||
var display = module.message || module.name; | ||
if (err) { | ||
if (verbose) { Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)')); } | ||
return cb(err); | ||
} | ||
if (verbose) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED')); } | ||
return cb(); | ||
}); | ||
} | ||
function installLangModule(module_name, cb) { | ||
@@ -552,0 +613,0 @@ var node_module_path = path.resolve(path.join(__dirname, '../../../')); |
@@ -195,2 +195,17 @@ { | ||
}, | ||
"v8": { | ||
"type": [ | ||
"boolean" | ||
] | ||
}, | ||
"event_loop_inspector": { | ||
"type": [ | ||
"boolean" | ||
] | ||
}, | ||
"deep_monitoring": { | ||
"type": [ | ||
"boolean" | ||
] | ||
}, | ||
"increment_var": { | ||
@@ -202,3 +217,7 @@ "type": "string" | ||
"default" : "NODE_APP_INSTANCE" | ||
}, | ||
"windowsHide": { | ||
"type": "boolean", | ||
"default" : true | ||
} | ||
} |
'use strict'; | ||
/** | ||
* Specialized PM2 CLI for Docker | ||
* Specialized PM2 CLI for Containers | ||
*/ | ||
@@ -13,16 +13,22 @@ var commander = require('commander'); | ||
var path = require('path'); | ||
var pm2; | ||
// Do not print banner | ||
process.env.PM2_DISCRETE_MODE = true; | ||
commander.version(pkg.version) | ||
.description('pm2-docker is a drop-in replacement node.js binary with some interesting production features') | ||
.description('pm2-runtime is a drop-in replacement Node.js binary for containers') | ||
.option('-i --instances <number>', 'launch [number] of processes automatically load-balanced. Increase overall performances and performance stability.') | ||
.option('--secret [key]', '[MONITORING] keymetrics secret key') | ||
.option('--no-autorestart', 'start an app without automatic restart') | ||
.option('--node-args <node_args>', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"') | ||
.option('-n --name <name>', 'set a <name> for script') | ||
.option('--max-memory-restart <memory>', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)') | ||
.option('-c --cron <cron_pattern>', 'restart a running process based on a cron pattern') | ||
.option('--interpreter <interpreter>', 'the interpreter pm2 should use for executing app (bash, python...)') | ||
.option('--public [key]', '[MONITORING] keymetrics public key') | ||
.option('--machine-name [name]', '[MONITORING] keymetrics machine name') | ||
.option('--raw', 'raw log output') | ||
.option('--trace', 'enable transaction tracing with km') | ||
.option('--v8', 'enable v8 data collecting') | ||
.option('--format', 'output logs formated like key=val') | ||
.option('--formatted', 'formatted log output |id|app|log') | ||
.option('--json', 'output logs in json format') | ||
.option('--format', 'output logs formated like key=val') | ||
.option('--delay <seconds>', 'delay start of configuration file by <seconds>', 0) | ||
@@ -36,38 +42,15 @@ .option('--web [port]', 'launch process web api on [port] (default to 9615)') | ||
.option('--output <path>', 'output log file destination (default disabled)', '/dev/null') | ||
.option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)') | ||
.allowUnknownOption() | ||
.usage('app.js'); | ||
function start(cmd, opts) { | ||
pm2 = new PM2.custom({ | ||
pm2_home : process.env.PM2_HOME || path.join(process.env.HOME, '.pm2'), | ||
secret_key : process.env.KEYMETRICS_SECRET || commander.secret, | ||
public_key : process.env.KEYMETRICS_PUBLIC || commander.public, | ||
machine_name : process.env.INSTANCE_NAME || commander.machineName, | ||
daemon_mode : true | ||
}); | ||
if (commander.autoExit) { | ||
autoExit(); | ||
} | ||
pm2.connect(function() { | ||
if (opts.web) { | ||
var port = opts.web === true ? cst.WEB_PORT : opts.web; | ||
pm2.web(port); | ||
} | ||
run(cmd, opts); | ||
}); | ||
} | ||
commander.command('*') | ||
.action(function(cmd){ | ||
start(cmd, commander); | ||
Runtime.instanciate(cmd); | ||
}); | ||
// @todo need to allow passing same option than pm2 start | ||
commander.command('start <app.js|json_file>') | ||
.description('start an application or json ecosystem file') | ||
.action(function(cmd) { | ||
start(cmd, commander); | ||
Runtime.instanciate(cmd); | ||
}); | ||
@@ -80,100 +63,125 @@ | ||
var autoExitIndex = process.argv.indexOf('--auto-exit'); | ||
if (autoExitIndex > -1) { | ||
console.warn( | ||
"Warning: --auto-exit has been removed, as it's now the default behavior" + | ||
"; if you want to disable it, use the new --no-auto-exit flag." | ||
); | ||
var Runtime = { | ||
pm2 : null, | ||
instanciate : function(cmd) { | ||
this.pm2 = new PM2.custom({ | ||
pm2_home : process.env.PM2_HOME || path.join(process.env.HOME, '.pm2'), | ||
secret_key : process.env.KEYMETRICS_SECRET || commander.secret, | ||
public_key : process.env.KEYMETRICS_PUBLIC || commander.public, | ||
machine_name : process.env.INSTANCE_NAME || commander.machineName, | ||
daemon_mode : process.env.PM2_RUNTIME_DEBUG || false | ||
}); | ||
process.argv.splice(autoExitIndex, 1); | ||
} | ||
this.pm2.connect(function(err, pm2_meta) { | ||
if (pm2_meta.new_pm2_instance == false) { | ||
console.warn('[WARN] PM2 Daemon is already running') | ||
} | ||
commander.parse(process.argv); | ||
process.on('SIGINT', function() { | ||
Runtime.exit(); | ||
}); | ||
process.on('SIGINT', function() { | ||
exitPM2(); | ||
}); | ||
process.on('SIGTERM', function() { | ||
Runtime.exit(); | ||
}); | ||
process.on('SIGTERM', function() { | ||
exitPM2(); | ||
}); | ||
Runtime.startLogStreaming(); | ||
Runtime.startApp(cmd, function(err) { | ||
if (err) { | ||
console.error(err.message || err); | ||
return Runtime.exit(); | ||
} | ||
}); | ||
}); | ||
}, | ||
function run(cmd, opts) { | ||
var needRaw = commander.raw; | ||
var timestamp = commander.timestamp; | ||
/** | ||
* Log Streaming Management | ||
*/ | ||
startLogStreaming : function() { | ||
if (commander.json === true) | ||
Log.jsonStream(this.pm2.Client, 'all'); | ||
else if (commander.format === true) | ||
Log.formatStream(this.pm2.Client, 'all', false, 'YYYY-MM-DD-HH:mm:ssZZ'); | ||
else | ||
Log.stream(this.pm2.Client, 'all', !commander.formatted, commander.timestamp, true); | ||
}, | ||
function exec() { | ||
pm2.start(cmd, opts, function(err, obj) { | ||
if (err) { | ||
console.error(err.message || err); | ||
return exitPM2(); | ||
} | ||
/** | ||
* Application Startup | ||
*/ | ||
startApp : function(cmd, cb) { | ||
function exec() { | ||
this.pm2.start(cmd, commander, function(err, obj) { | ||
if (err) | ||
return cb(err); | ||
if (obj && obj.length == 0) | ||
return cb(new Error('Failed to start application')) | ||
var pm_id = obj[0].pm2_env.pm_id; | ||
if (commander.web) { | ||
var port = commander.web === true ? cst.WEB_PORT : commander.web; | ||
Runtime.pm2.web(port); | ||
} | ||
if (commander.json === true) | ||
Log.jsonStream(pm2.Client, pm_id); | ||
else if (commander.format === true) | ||
Log.formatStream(pm2.Client, pm_id, false, 'YYYY-MM-DD-HH:mm:ssZZ'); | ||
else | ||
Log.stream(pm2.Client, 'all', needRaw, timestamp, false); | ||
if (commander.autoExit) | ||
Runtime.autoExitWorker(); | ||
if (process.env.PM2_RUNTIME_DEBUG) | ||
pm2.disconnect(function() {}); | ||
// For Testing purpose (allow to auto exit CLI) | ||
if (process.env.PM2_RUNTIME_DEBUG) | ||
Runtime.pm2.disconnect(function() {}); | ||
}); | ||
} | ||
setTimeout(exec.bind(this), opts.delay * 1000); | ||
} | ||
return cb(null, obj); | ||
}); | ||
} | ||
// via --delay <seconds> option | ||
setTimeout(exec.bind(this), commander.delay * 1000); | ||
}, | ||
function exitPM2() { | ||
console.log('Exiting PM2'); | ||
pm2.kill(function() { | ||
process.exit(0); | ||
}); | ||
} | ||
/** | ||
* Exit runtime mgmt | ||
*/ | ||
exit : function() { | ||
if (!this.pm2) return process.exit(1); | ||
/** | ||
* Exit current PM2 instance if 0 app is online | ||
* function activated via --auto-exit | ||
*/ | ||
function autoExit() { | ||
var interval = 3000; | ||
var aliveInterval = interval * 1.5; | ||
this.pm2.kill(function() { | ||
process.exit(0); | ||
}); | ||
}, | ||
setTimeout(function () { | ||
var alive = false | ||
var aliveTimer = setTimeout(function () { | ||
if (!alive) { | ||
console.error('PM2 Daemon is dead'); | ||
process.exit(1); | ||
} | ||
}, aliveInterval); | ||
/** | ||
* Exit current PM2 instance if 0 app is online | ||
* function activated via --auto-exit | ||
*/ | ||
autoExitWorker : function() { | ||
var interval = 1000; | ||
pm2.list(function (err, apps) { | ||
if (err) { | ||
console.log('pm2.list got error') | ||
console.error(err); | ||
exitPM2(); | ||
} | ||
var timer = setTimeout(function () { | ||
Runtime.pm2.list(function (err, apps) { | ||
if (err) { | ||
console.error('Could not run pm2 list'); | ||
return Runtime.autoExitWorker(); | ||
} | ||
clearTimeout(aliveTimer); | ||
alive = true; | ||
var appOnline = 0; | ||
var appOnline = 0; | ||
apps.forEach(function (app) { | ||
if (app.pm2_env.status === cst.ONLINE_STATUS || | ||
app.pm2_env.status === cst.LAUNCHING_STATUS) { | ||
appOnline++; | ||
} | ||
}); | ||
apps.forEach(function (app) { | ||
if (app.pm2_env.status === cst.ONLINE_STATUS || | ||
app.pm2_env.status === cst.LAUNCHING_STATUS) { | ||
appOnline++; | ||
if (appOnline === 0) { | ||
console.log('0 application online, exiting'); | ||
return Runtime.exit(); | ||
} | ||
Runtime.autoExitWorker(); | ||
}); | ||
}, interval); | ||
if (appOnline === 0) { | ||
console.log('0 application online, exiting'); | ||
exitPM2(); | ||
} | ||
autoExit(); | ||
}); | ||
}, interval); | ||
timer.unref(); | ||
} | ||
} | ||
commander.parse(process.argv); |
@@ -72,3 +72,4 @@ /** | ||
rpc_socket_file : that.conf.DAEMON_RPC_PORT, | ||
pid_file : that.conf.PM2_PID_FILE_PATH | ||
pid_file : that.conf.PM2_PID_FILE_PATH, | ||
ignore_signals : true | ||
}); | ||
@@ -90,3 +91,3 @@ | ||
daemon_mode : that.conf.daemon_mode, | ||
new_pm2_instance : false, | ||
new_pm2_instance : true, | ||
rpc_socket_file : that.rpc_socket_file, | ||
@@ -93,0 +94,0 @@ pub_socket_file : that.pub_socket_file, |
@@ -23,2 +23,3 @@ /** | ||
this.ignore_signals = opts.ignore_signals || false; | ||
this.rpc_socket_ready = false; | ||
@@ -93,3 +94,4 @@ this.pub_socket_ready = false; | ||
this.handleSignals(); | ||
if (this.ignore_signals != true) | ||
this.handleSignals(); | ||
@@ -260,7 +262,2 @@ /** | ||
fmt.sep(); | ||
fmt.title('Stopping PM2'); | ||
fmt.field('Time', new Date()); | ||
fmt.sep(); | ||
/** | ||
@@ -270,5 +267,3 @@ * Cleanly kill pm2 | ||
that.rpc_socket.close(function() { | ||
console.log('RPC closed'); | ||
that.pub_socket.close(function() { | ||
console.log('PUB closed'); | ||
@@ -342,3 +337,3 @@ // notify cli that the daemon is shuting down (only under unix since windows doesnt handle signals) | ||
} catch(e) {} | ||
console.log('[PM2] Exited peacefully'); | ||
console.log('Exited peacefully'); | ||
process.exit(0); | ||
@@ -345,0 +340,0 @@ }); |
@@ -34,2 +34,3 @@ /** | ||
cluster.setupMaster({ | ||
windowsHide: true, | ||
exec : path.resolve(path.dirname(module.filename), 'ProcessContainer.js') | ||
@@ -362,3 +363,3 @@ }); | ||
if (God.pm2_being_killed) { | ||
console.log('[HandleExit] PM2 is being killed, stopping restart procedure...'); | ||
//console.log('[HandleExit] PM2 is being killed, stopping restart procedure...'); | ||
return false; | ||
@@ -456,3 +457,3 @@ } | ||
proc.pm2_env.status == cst.STOPPING_STATUS) { | ||
return console.error('Proc is not defined anymore or is being killed'); | ||
return console.error('Cancelling versioning data parsing'); | ||
} | ||
@@ -459,0 +460,0 @@ |
@@ -93,2 +93,8 @@ /** | ||
var windowsHide; | ||
if (typeof(pm2_env.windowsHide) === "boolean") { | ||
windowsHide = pm2_env.windowsHide; | ||
} else { | ||
windowsHide = true; | ||
} | ||
try { | ||
@@ -98,3 +104,3 @@ var cspr = spawn(command, args, { | ||
detached : true, | ||
windowsHide: true, | ||
windowsHide: windowsHide, | ||
cwd : pm2_env.pm_cwd || process.cwd(), | ||
@@ -101,0 +107,0 @@ stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core |
@@ -235,3 +235,3 @@ /** | ||
UX.processing.start(); | ||
console.log('[KM] Connecting'); | ||
@@ -250,4 +250,2 @@ fs.writeFileSync(conf.INTERACTOR_PID_PATH, child.pid); | ||
var t = setTimeout(function() { | ||
UX.processing.stop(); | ||
Common.printOut(cst.PREFIX_MSG_WARNING + ' Not managed to connect to Keymetrics, retrying in background. (check %s)', cst.INTERACTOR_LOG_FILE_PATH); | ||
@@ -264,4 +262,2 @@ child.removeAllListeners('message'); | ||
UX.processing.stop(); | ||
if (msg.debug) { | ||
@@ -268,0 +264,0 @@ return cb(null, msg, child); |
@@ -33,7 +33,11 @@ /** | ||
if (process.env.pmx !== 'false') | ||
if (process.env.pmx !== 'false') { | ||
require('pmx').init({ | ||
transactions: process.env.km_link == 'true' && process.env.trace == 'true' || false, | ||
http: process.env.km_link == 'true' || false | ||
transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, | ||
http: process.env.km_link === 'true' || false, | ||
v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, | ||
event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, | ||
deep_metrics: process.env.deep_monitoring === 'true' || false | ||
}); | ||
} | ||
@@ -43,3 +47,2 @@ var stdFile = pm2_env.pm_log_path; | ||
var errFile = pm2_env.pm_err_log_path; | ||
var pmId = pm2_env.pm_id; | ||
var pidFile = pm2_env.pm_pid_path; | ||
@@ -46,0 +49,0 @@ var script = pm2_env.pm_exec_path; |
@@ -7,6 +7,9 @@ /** | ||
// Inject custom modules | ||
if (process.env.pmx !== "false") { | ||
if (process.env.pmx !== 'false') { | ||
require('pmx').init({ | ||
transactions: process.env.km_link == 'true' && process.env.trace == 'true' || false, | ||
http: process.env.km_link == 'true' || false | ||
transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, | ||
http: process.env.km_link === 'true' || false, | ||
v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, | ||
event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, | ||
deep_metrics: process.env.deep_monitoring === 'true' || false | ||
}); | ||
@@ -65,3 +68,3 @@ } | ||
// If no gid specified - set gid to uid | ||
var new_gid = process.env.gid == null ? process.env.uid : process.env.gid; | ||
var new_gid = process.env.gid == null ? process.env.uid : process.env.gid; | ||
process.initgroups(process.env.uid, new_gid); | ||
@@ -68,0 +71,0 @@ process.setgid(new_gid); |
@@ -17,3 +17,3 @@ 'use strict'; | ||
case 'win32': | ||
exec('taskkill /pid ' + pid + ' /T /F', callback); | ||
exec('taskkill /pid ' + pid + ' /T /F', { windowsHide: true }, callback); | ||
break; | ||
@@ -20,0 +20,0 @@ case 'darwin': |
@@ -87,3 +87,3 @@ /** | ||
function timestamp(){ | ||
return moment().format(cst.PM2_LOG_DATE_FORMAT) + ': '; | ||
return '[' + moment().format(cst.PM2_LOG_DATE_FORMAT) + ']'; | ||
} | ||
@@ -112,3 +112,3 @@ | ||
// do not destroy variable insertion | ||
arguments[0] && (arguments[0] = timestamp() + arguments[0]); | ||
arguments[0] && (arguments[0] = timestamp() + ' PM2 ' + k + ': ' + arguments[0]); | ||
consoled[k].apply(console, arguments); | ||
@@ -228,8 +228,10 @@ }; | ||
else if(canonic_module_name.indexOf('/') !== -1) { | ||
canonic_module_name = canonic_module_name.split('/')[1]; | ||
if (canonic_module_name.charAt(0) !== "@"){ | ||
canonic_module_name = canonic_module_name.split('/')[1]; | ||
} | ||
} | ||
//pm2 install module@2.1.0-beta | ||
if(canonic_module_name.indexOf('@') !== -1) { | ||
canonic_module_name = canonic_module_name.split('@')[0]; | ||
//pm2 install @somescope/module@2.1.0-beta | ||
if(canonic_module_name.lastIndexOf('@') > 0) { | ||
canonic_module_name = canonic_module_name.substr(0,canonic_module_name.lastIndexOf("@")); | ||
} | ||
@@ -236,0 +238,0 @@ |
{ | ||
"name": "pm2", | ||
"preferGlobal": true, | ||
"version": "2.9.3", | ||
"version": "2.10.0", | ||
"engines": { | ||
@@ -165,5 +165,5 @@ "node": ">=0.12" | ||
"chalk": "^1.1", | ||
"chokidar": "^1.7", | ||
"chokidar": "^2", | ||
"cli-table-redemption": "^1.0.0", | ||
"commander": "2.12.2", | ||
"commander": "2.13.0", | ||
"cron": "^1.3", | ||
@@ -175,2 +175,3 @@ "debug": "^3.0", | ||
"moment": "^2.19", | ||
"needle": "^2.1.0", | ||
"nssocket": "0.6.0", | ||
@@ -182,3 +183,4 @@ "pidusage": "^1.2.0", | ||
"pm2-multimeter": "^0.1.2", | ||
"pmx": "~1.5.*", | ||
"pmx": "^1.6", | ||
"promptly": "2.2.0", | ||
"semver": "^5.3", | ||
@@ -188,7 +190,5 @@ "shelljs": "0.7.8", | ||
"sprintf-js": "1.1.1", | ||
"v8-compile-cache": "^1.1.0", | ||
"vizion": "^0.2", | ||
"yamljs": "^0.3.0", | ||
"needle": "1.6.0", | ||
"promptly": "2.2.0", | ||
"v8-compile-cache": "^1.1.0" | ||
"yamljs": "^0.3.0" | ||
}, | ||
@@ -195,0 +195,0 @@ "devDependencies": { |
284
README.md
@@ -12,4 +12,4 @@ <div align="center"> | ||
<a href="https://www.bithound.io/github/Unitech/pm2" title="Bithound PM2 score"> | ||
<img src="https://www.bithound.io/github/Unitech/pm2/badges/score.svg" alt="bitHound Score"> | ||
<a href="https://badge.fury.io/js/pm2"> | ||
<img src="https://badge.fury.io/js/pm2.svg" alt="npm version" height="18"> | ||
</a> | ||
@@ -31,4 +31,10 @@ | ||
PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks. | ||
PM2 is a General Purpose Process Manager and a Production Runtime for Node.js apps with a built-in Load Balancer. | ||
Key features: | ||
- Simple and efficient process management (start/stop/restart/delete/show/monit) | ||
- Keep your application ALWAYS ONLINE with auto restarts and init system script generation | ||
- Clusterize Node.js Applications without code change to increase performance and reliability | ||
- Hot Reload Node.js Applications without extra configuration | ||
Starting an application in production mode is as easy as: | ||
@@ -40,3 +46,3 @@ | ||
PM2 is constantly assailed by [more than 1400 tests](https://travis-ci.org/Unitech/pm2). | ||
PM2 is constantly assailed by [more than 1800 tests](https://travis-ci.org/Unitech/pm2). | ||
@@ -50,3 +56,3 @@ Official website: [http://pm2.keymetrics.io/](http://pm2.keymetrics.io/) | ||
## Install PM2 | ||
### Installing PM2 | ||
@@ -59,4 +65,6 @@ ```bash | ||
## Start an application | ||
### Start an application | ||
You can start any application (Node.js, Python, Ruby, binaries in $PATH...) like that: | ||
```bash | ||
@@ -70,166 +78,136 @@ $ pm2 start app.js | ||
## Container Support | ||
### Managing a Process | ||
Using Containers? We got your back with pm2-runtime, a dedicated command for running Node.js in containers and our [officialy suported Docker image](https://hub.docker.com/r/keymetrics/pm2/). | ||
Once applications are started you can manage them easily: | ||
Using it: | ||
![Process listing](https://github.com/unitech/pm2/raw/master/pres/pm2-list.png) | ||
To list all running processes: | ||
```bash | ||
$ pm2 list | ||
``` | ||
FROM keymetrics/pm2:latest-alpine | ||
[...] | ||
CMD [ "pm2-runtime", "ecosystem.config.js" ] | ||
Managing processes is straightforward: | ||
```bash | ||
$ pm2 stop <app_name|id|'all'|json_conf> | ||
$ pm2 restart <app_name|id|'all'|json_conf> | ||
$ pm2 delete <app_name|id|'all'|json_conf> | ||
``` | ||
[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/) | ||
To have more details on a specific process: | ||
## Monitor PM2 and Applications | ||
```bash | ||
$ pm2 describe <id|app_name> | ||
``` | ||
To monitor your applications just type: | ||
To monitor logs, custom metrics, process information: | ||
```bash | ||
$ pm2 register | ||
$ pm2 monit | ||
``` | ||
[More about PM2 Monitoring](http://docs.keymetrics.io/) | ||
[More about Process Management](http://pm2.keymetrics.io/docs/usage/process-management/) | ||
## Updating PM2 | ||
### Cluster Mode: Node.js Load Balancing & Hot Reload | ||
The Cluster mode is a special mode when starting a Node.js application, it starts multiple processes and load-balance HTTP/TCP/UDP queries between them. This increase overall performance (by a factor of x10 on 16 cores machines) and reliability (faster socket re-balancing in case of unhandled errors). | ||
Starting a Node.js application in cluster mode that will leverage all CPUs available: | ||
```bash | ||
# Install latest PM2 version | ||
$ npm install pm2@latest -g | ||
# Save process list, exit old PM2 & restore all processes | ||
$ pm2 update | ||
$ pm2 start api.js -i <processes> | ||
``` | ||
*PM2 updates are seamless* | ||
`<processes>` can be `'max'`, `-1` (all cpu minus 1) or a specified number of instances to start. | ||
## Main features | ||
**Hot Reload** | ||
### Commands overview | ||
Hot Reload allows to update an application without any downtime: | ||
```bash | ||
# General | ||
$ npm install pm2 -g # Install PM2 | ||
$ pm2 start app.js # Start, Daemonize and auto-restart application (Node) | ||
$ pm2 start app.py # Start, Daemonize and auto-restart application (Python) | ||
$ pm2 start npm -- start # Start, Daemonize and auto-restart Node application | ||
$ pm2 reload all | ||
``` | ||
# Cluster Mode (Node.js only) | ||
$ pm2 start app.js -i 4 # Start 4 instances of application in cluster mode | ||
# it will load balance network queries to each app | ||
$ pm2 reload all # Zero Second Downtime Reload | ||
$ pm2 scale [app-name] 10 # Scale Cluster app to 10 process | ||
Seamlessly supported by all major Node.js frameworks and any Node.js applications without any code change: | ||
# Process Monitoring | ||
$ pm2 list # List all processes started with PM2 | ||
$ pm2 list --sort=<field> # Sort all processes started with PM2 | ||
$ pm2 monit # Display memory and cpu usage of each app | ||
$ pm2 show [app-name] # Show all information about application | ||
![Framework supported](https://raw.githubusercontent.com/Unitech/PM2/development/pres/cluster-support.png) | ||
# Log management | ||
$ pm2 logs # Display logs of all apps | ||
$ pm2 logs [app-name] # Display logs for a specific app | ||
$ pm2 logs --json # Logs in JSON format | ||
$ pm2 flush | ||
$ pm2 reloadLogs | ||
[More informations about how PM2 make clustering easy](https://keymetrics.io/2015/03/26/pm2-clustering-made-easy/) | ||
# Process State Management | ||
$ pm2 start app.js --name="api" # Start application and name it "api" | ||
$ pm2 start app.js -- -a 34 # Start app and pass option "-a 34" as argument | ||
$ pm2 start app.js --watch # Restart application on file change | ||
$ pm2 start script.sh # Start bash script | ||
$ pm2 start app.json # Start all applications declared in app.json | ||
$ pm2 reset [app-name] # Reset all counters | ||
$ pm2 stop all # Stop all apps | ||
$ pm2 stop 0 # Stop process with id 0 | ||
$ pm2 restart all # Restart all apps | ||
$ pm2 gracefulReload all # Gracefully reload all apps in cluster mode | ||
$ pm2 delete all # Kill and delete all apps | ||
$ pm2 delete 0 # Delete app with id 0 | ||
### Container Support | ||
# Startup/Boot management | ||
$ pm2 startup # Detect init system, generate and configure pm2 boot on startup | ||
$ pm2 save # Save current process list | ||
$ pm2 resurrect # Restore previously saved processes | ||
$ pm2 unstartup # Disable and remove startup system | ||
With the drop-in replacement command for `node`, called `pm2-runtime`, run your Node.js application in a proper production environment. | ||
We also offer an [officialy supported Docker image](https://hub.docker.com/r/keymetrics/pm2/). | ||
$ pm2 update # Save processes, kill PM2 and restore processes | ||
$ pm2 generate # Generate a sample json configuration file | ||
Using it is seamless: | ||
# Deployment | ||
$ pm2 deploy app.json prod setup # Setup "prod" remote server | ||
$ pm2 deploy app.json prod # Update "prod" remote server | ||
$ pm2 deploy app.json prod revert 2 # Revert "prod" remote server by 2 | ||
# Module system | ||
$ pm2 module:generate [name] # Generate sample module with name [name] | ||
$ pm2 install pm2-logrotate # Install module (here a log rotation system) | ||
$ pm2 uninstall pm2-logrotate # Uninstall module | ||
$ pm2 publish # Increment version, git push and npm publish | ||
``` | ||
FROM keymetrics/pm2:latest-alpine | ||
[...] | ||
CMD [ "pm2-runtime", "npm", "--", "start" ] | ||
``` | ||
### Process management | ||
[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/) | ||
Once applications are started you can list and manage them easily: | ||
### Terminal Based Monitoring | ||
![Process listing](https://github.com/unitech/pm2/raw/master/pres/pm2-list.png) | ||
![Monit](https://github.com/Unitech/pm2/raw/master/pres/pm2-monit.png) | ||
Listing all running processes: | ||
Monitor all processes launched straight from the command line: | ||
```bash | ||
$ pm2 list | ||
$ pm2 monit | ||
``` | ||
Managing your processes is straightforward: | ||
### Monitor PM2 and Applications with our SaaS | ||
```bash | ||
$ pm2 stop <app_name|id|'all'|json_conf> | ||
$ pm2 restart <app_name|id|'all'|json_conf> | ||
$ pm2 delete <app_name|id|'all'|json_conf> | ||
``` | ||
To make sure it re-evaluates enviroment variables declared in your `json_conf` pass it as argument, and optionally your custom `env` name from your `json_conf` if any: | ||
```bash | ||
$ pm2 restart <json_conf> [--env <env_name>] | ||
``` | ||
Once you deploy your application in production, you can monitor, debug and profile it externally with our [SaaS Monitoring](https://keymetrics.io). | ||
To have more details on a specific process: | ||
To start monitoring applications from the terminal: | ||
```bash | ||
$ pm2 describe <id|app_name> | ||
$ pm2 register | ||
``` | ||
[More about Process Management](http://pm2.keymetrics.io/docs/usage/process-management/) | ||
[More about PM2 Monitoring](http://docs.keymetrics.io/) | ||
### Load Balancing & Zero second Downtime Reload | ||
### Expose Custom Metrics | ||
When an application is started with the -i <instance_number> option, the **Cluster Mode** is enabled. | ||
To get more insights on how your application behave, plug custom metrics inside your code and monitor them with the `pm2 monit` command: | ||
The Cluster Mode starts <instance_number> instances of your app and automatically load balance HTTP/TCP/UDP between each instance. This allows to increase overall performance depending on the number of CPUs available. | ||
In your project install [pmx](https://github.com/keymetrics/pmx): | ||
Seamlessly supported by all major Node.js frameworks and any Node.js applications without any code change: | ||
```bash | ||
$ npm install pmx --save | ||
``` | ||
![Framework supported](https://raw.githubusercontent.com/Unitech/PM2/development/pres/cluster-support.png) | ||
Then plug a custom metric: | ||
Main commands: | ||
```javascript | ||
var Probe = require('pmx').probe(); | ||
```bash | ||
$ pm2 start app.js -i max # Enable load-balancer and start 'max' instances (cpu nb) | ||
var counter = 1; | ||
$ pm2 reload all # Zero second dowtime reload | ||
var metric = Probe.metric({ | ||
name : 'Counter', | ||
value : function() { | ||
return counter; | ||
} | ||
}); | ||
$ pm2 scale <app_name> <instance_number> # Increase / Decrease process number | ||
setInterval(function() { | ||
counter++; | ||
}, 1000); | ||
``` | ||
[More informations about how PM2 make clustering easy](https://keymetrics.io/2015/03/26/pm2-clustering-made-easy/) | ||
Then to see the metric type from in the terminal: | ||
### CPU / Memory Monitoring | ||
![Monit](https://github.com/Unitech/pm2/raw/master/pres/pm2-monit.png) | ||
Monitoring all processes launched: | ||
```bash | ||
$ pm2 monit | ||
$ pm2 monitor | ||
``` | ||
Metric, Counter, Histogram and Meters are [available](http://pm2.keymetrics.io/docs/usage/process-metrics/) | ||
### Log facilities | ||
@@ -239,3 +217,3 @@ | ||
Displaying logs of a specified process or all processes, in real time. Standard, Raw, JSON and formated output are available. | ||
Displaying logs of a specified process or all processes, in real time is easy: | ||
@@ -246,2 +224,4 @@ ```bash | ||
Standard, Raw, JSON and formated output are available. | ||
Examples: | ||
@@ -262,3 +242,3 @@ | ||
PM2 can generate and configure a startup script to keep PM2 and your processes alive at every server restart. | ||
PM2 can generates and configure a startup script to keep PM2 and your processes alive at every server restart. | ||
@@ -287,2 +267,78 @@ Supports init systems like: **systemd** (Ubuntu 16, CentOS, Arch), **upstart** (Ubuntu 14/12), **launchd** (MacOSx, Darwin), **rc.d** (FreeBSD). | ||
### Commands Cheatsheet | ||
```bash | ||
# General | ||
$ npm install pm2 -g # Install PM2 | ||
$ pm2 start app.js # Start, Daemonize and auto-restart application (Node) | ||
$ pm2 start app.py # Start, Daemonize and auto-restart application (Python) | ||
$ pm2 start npm -- start # Start, Daemonize and auto-restart Node application | ||
# Cluster Mode (Node.js only) | ||
$ pm2 start app.js -i 4 # Start 4 instances of application in cluster mode | ||
# it will load balance network queries to each app | ||
$ pm2 reload all # Zero Second Downtime Reload | ||
$ pm2 scale [app-name] 10 # Scale Cluster app to 10 process | ||
# Process Monitoring | ||
$ pm2 list # List all processes started with PM2 | ||
$ pm2 list --sort=<field> # Sort all processes started with PM2 | ||
$ pm2 monit # Display memory and cpu usage of each app | ||
$ pm2 show [app-name] # Show all information about application | ||
# Log management | ||
$ pm2 logs # Display logs of all apps | ||
$ pm2 logs [app-name] # Display logs for a specific app | ||
$ pm2 logs --json # Logs in JSON format | ||
$ pm2 flush | ||
$ pm2 reloadLogs | ||
# Process State Management | ||
$ pm2 start app.js --name="api" # Start application and name it "api" | ||
$ pm2 start app.js -- -a 34 # Start app and pass option "-a 34" as argument | ||
$ pm2 start app.js --watch # Restart application on file change | ||
$ pm2 start script.sh # Start bash script | ||
$ pm2 start app.json # Start all applications declared in app.json | ||
$ pm2 reset [app-name] # Reset all counters | ||
$ pm2 stop all # Stop all apps | ||
$ pm2 stop 0 # Stop process with id 0 | ||
$ pm2 restart all # Restart all apps | ||
$ pm2 gracefulReload all # Gracefully reload all apps in cluster mode | ||
$ pm2 delete all # Kill and delete all apps | ||
$ pm2 delete 0 # Delete app with id 0 | ||
# Startup/Boot management | ||
$ pm2 startup # Detect init system, generate and configure pm2 boot on startup | ||
$ pm2 save # Save current process list | ||
$ pm2 resurrect # Restore previously saved processes | ||
$ pm2 unstartup # Disable and remove startup system | ||
$ pm2 update # Save processes, kill PM2 and restore processes | ||
$ pm2 init # Generate a sample js configuration file | ||
# Deployment | ||
$ pm2 deploy app.json prod setup # Setup "prod" remote server | ||
$ pm2 deploy app.json prod # Update "prod" remote server | ||
$ pm2 deploy app.json prod revert 2 # Revert "prod" remote server by 2 | ||
# Module system | ||
$ pm2 module:generate [name] # Generate sample module with name [name] | ||
$ pm2 install pm2-logrotate # Install module (here a log rotation system) | ||
$ pm2 uninstall pm2-logrotate # Uninstall module | ||
$ pm2 publish # Increment version, git push and npm publish | ||
``` | ||
Also check out the [example folder](https://github.com/Unitech/pm2/tree/master/examples) to discover all features. | ||
## Updating PM2 | ||
```bash | ||
# Install latest PM2 version | ||
$ npm install pm2@latest -g | ||
# Save process list, exit old PM2 & restore all processes | ||
$ pm2 update | ||
``` | ||
*PM2 updates are seamless* | ||
## Module system | ||
@@ -289,0 +345,0 @@ |
@@ -173,2 +173,10 @@ // Type definitions for pm2 2.7.1 | ||
/** | ||
* - Send an set of data as object to a specific process | ||
* @param proc_id | ||
* @param packet | ||
* @param cb | ||
*/ | ||
export function sendDataToProcessId(proc_id: number, packet: object, cb: ErrResultCallback): void; | ||
// Interfaces | ||
@@ -379,3 +387,3 @@ | ||
*/ | ||
watch?: boolean; | ||
watch?: boolean|string[]; | ||
/** | ||
@@ -382,0 +390,0 @@ * (Default: false) By default, pm2 will only start a script if that script isn’t |
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances 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
763819
108
17267
386
325
+ Addedanymatch@2.0.0(transitive)
+ Addedchokidar@2.1.8(transitive)
+ Addedcommander@2.13.0(transitive)
+ Addeddeep-metrics@0.0.1(transitive)
+ Addedglob-parent@3.1.0(transitive)
+ Addedis-extglob@2.1.1(transitive)
+ Addedis-glob@3.1.04.0.3(transitive)
+ Addedneedle@2.9.1(transitive)
+ Addednormalize-path@3.0.0(transitive)
+ Addedpath-dirname@1.0.2(transitive)
+ Addedpmx@1.6.7(transitive)
+ Addedsax@1.4.1(transitive)
+ Addedupath@1.2.0(transitive)
- Removedanymatch@1.3.2(transitive)
- Removedarr-diff@2.0.0(transitive)
- Removedarray-unique@0.2.1(transitive)
- Removedbraces@1.8.5(transitive)
- Removedchokidar@1.7.0(transitive)
- Removedcommander@2.12.2(transitive)
- Removedexpand-brackets@0.1.5(transitive)
- Removedexpand-range@1.8.2(transitive)
- Removedextglob@0.3.2(transitive)
- Removedfilename-regex@2.0.1(transitive)
- Removedfill-range@2.2.4(transitive)
- Removedfor-own@0.1.5(transitive)
- Removedglob-base@0.3.0(transitive)
- Removedglob-parent@2.0.0(transitive)
- Removedis-dotfile@1.0.3(transitive)
- Removedis-equal-shallow@0.1.3(transitive)
- Removedis-extglob@1.0.0(transitive)
- Removedis-glob@2.0.1(transitive)
- Removedis-number@2.1.04.0.0(transitive)
- Removedis-posix-bracket@0.1.1(transitive)
- Removedis-primitive@2.0.0(transitive)
- Removedmath-random@1.0.4(transitive)
- Removedmicromatch@2.3.11(transitive)
- Removedneedle@1.6.0(transitive)
- Removedobject.omit@2.0.1(transitive)
- Removedparse-glob@3.0.4(transitive)
- Removedpmx@1.5.6(transitive)
- Removedpreserve@0.2.0(transitive)
- Removedrandomatic@3.1.1(transitive)
- Removedregex-cache@0.4.4(transitive)
Updatedchokidar@^2
Updatedcommander@2.13.0
Updatedneedle@^2.1.0
Updatedpmx@^1.6