Merge branch 'development' into master

This commit is contained in:
Vincent Vallet 2018-03-19 09:37:28 +01:00 committed by GitHub
commit f5668331db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 2108 additions and 2112 deletions

View File

@ -4,7 +4,6 @@ node_js:
- "4"
- "6"
- "8"
- "0.12"
os:
- linux
before_install:

View File

@ -32,7 +32,7 @@
- [Without Keymetrics](#without-keymetrics)
- [With Keymetrics](#with-keymetrics)
### Deployment - ecosystem.json
### Deployment - ecosystem.config.js
- [Getting started with deployment](#deployment)
- [Deployment options](#deployment-help)

View File

@ -13,7 +13,7 @@
<img src="https://badge.fury.io/js/pm2.svg" alt="npm version" height="18">
</a>
<a href="https://www.npmjs.com/package/pm2" title="PM2 on NPM">
<a href="https://npmcharts.com/compare/pm2?minimal=true" title="PM2 on NPM">
<img alt="NPM Downloads" src="https://img.shields.io/npm/dm/pm2.svg?style=flat-square"/>
</a>
@ -70,6 +70,21 @@ Your app is now daemonized, monitored and kept alive forever.
[More about Process Management](http://pm2.keymetrics.io/docs/usage/process-management/)
### Container Support
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/).
Using it is seamless:
```
FROM keymetrics/pm2:latest-alpine
[...]
CMD [ "pm2-runtime", "npm", "--", "start" ]
```
[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/)
### Managing a Process
Once applications are started you can manage them easily:
@ -130,21 +145,6 @@ Seamlessly supported by all major Node.js frameworks and any Node.js application
[More informations about how PM2 make clustering easy](https://keymetrics.io/2015/03/26/pm2-clustering-made-easy/)
### Container Support
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/).
Using it is seamless:
```
FROM keymetrics/pm2:latest-alpine
[...]
CMD [ "pm2-runtime", "npm", "--", "start" ]
```
[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/)
### Terminal Based Monitoring
![Monit](https://github.com/Unitech/pm2/raw/master/pres/pm2-monit.png)
@ -293,7 +293,6 @@ $ 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

193
bin/pm2
View File

@ -33,24 +33,29 @@ if (process.argv.indexOf('-v') > -1) {
var pm2 = new PM2();
commander.version(pkg.version)
.option('-v --version', 'get version')
.option('-v --version', 'print pm2 version')
.option('-s --silent', 'hide all messages', false)
.option('-n --name <name>', 'set a name for the process in the process list')
.option('-m --mini-list', 'display a compacted list without formatting')
.option('--interpreter <interpreter>', 'set a specific interpreter to use for executing app, default: node')
.option('--interpreter-args <arguments>', 'set arguments to pass to the interpreter (alias of --node-args)')
.option('--node-args <node_args>', 'space delimited arguments to pass to node')
.option('-o --output <path>', 'specify log file for stdout')
.option('-e --error <path>', 'specify log file for stderr')
.option('-l --log [path]', 'specify log file which gathers both stdout and stderr')
.option('--log-type <type>', 'specify log output style (raw by default, json optional)')
.option('--log-date-format <date format>', 'add custom prefix timestamp to logs')
.option('--disable-logs', 'disable all logs storage')
.option('--env <environment_name>', 'specify which set of environment variables from ecosystem file must be injected')
.option('-a --update-env', 'force an update of the environment with restart/reload (-a <=> apply)')
.option('-f --force', 'force actions')
.option('--disable-logs', 'do not write logs')
.option('-n --name <name>', 'set a <name> for script')
.option('-i --instances <number>', 'launch [number] instances (for networked app)(load balanced)')
.option('--parallel <number>', 'number of parallel actions (for restart/reload)')
.option('-l --log [path]', 'specify entire log file (error and out are both included)')
.option('-o --output <path>', 'specify out log file')
.option('-e --error <path>', 'specify error log file')
.option('-p --pid <pid>', 'specify pid file')
.option('-k --kill-timeout <delay>', 'delay before sending final SIGKILL signal to process')
.option('--listen-timeout <delay>', 'listen timeout on application reload')
.option('--max-memory-restart <memory>', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)')
.option('--max-memory-restart <memory>', 'Restart the app if an amount of memory is exceeded (in bytes)')
.option('--restart-delay <delay>', 'specify a delay between restarts (in milliseconds)')
.option('--env <environment_name>', 'specify environment to get specific env variables (for JSON declaration)')
.option('--log-type <type>', 'specify log output style (raw by default, json optional)')
.option('-x --execute-command', 'execute a program using fork system')
.option('--max-restarts [count]', 'only restart the script COUNT times')
.option('-u --user <username>', 'define user when generating startup script')
@ -62,19 +67,14 @@ commander.version(pkg.version)
.option('--service-name <name>', 'define service name when generating startup script')
.option('-c --cron <cron_pattern>', 'restart a running process based on a cron pattern')
.option('-w --write', 'write configuration in local folder')
.option('--interpreter <interpreter>', 'the interpreter pm2 should use for executing app (bash, python...)')
.option('--interpreter-args <arguments>', 'interpret options (alias of --node-args)')
.option('--log-date-format <date format>', 'add custom prefix timestamp to logs')
.option('--no-daemon', 'run pm2 daemon in the foreground if it doesn\'t exist already')
.option('-a --update-env', 'update environment on restart/reload (-a <=> apply)')
.option('--source-map-support', 'force source map support')
.option('--only <application-name>', 'with json declaration, allow to only act on one application')
.option('--disable-source-map-support', 'force source map support')
.option('--wait-ready', 'ask pm2 to wait for ready event from your app')
.option('--merge-logs', 'merge logs from different instances but keep error and out separated')
.option('--watch [paths]', 'watch application folder for changes', function(v, m) { m.push(v); return m;}, [])
.option('--ignore-watch <folders|files>', 'folder/files to be ignored watching, should be a specific name or regex - e.g. --ignore-watch="test node_modules \"some scripts\""')
.option('--node-args <node_args>', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"')
.option('--ignore-watch <folders|files>', 'List of paths to ignore (name or regex)')
.option('--no-color', 'skip colors')
.option('--no-vizion', 'start an app without vizion feature (versioning control)')
.option('--no-autorestart', 'start an app without automatic restart')
@ -90,38 +90,50 @@ commander.version(pkg.version)
.option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)')
.usage('[cmd] app');
commander.on('--help', function() {
console.log(' Basic Examples:');
console.log('');
console.log(' Start an app using all CPUs available + set a name :');
console.log(' $ pm2 start app.js -i 0 --name "api"');
console.log('');
console.log(' Restart the previous app launched, by name :');
console.log(' $ pm2 restart api');
console.log('');
console.log(' Stop the app :');
console.log(' $ pm2 stop api');
console.log('');
console.log(' Restart the app that is stopped :');
console.log(' $ pm2 restart api');
console.log('');
console.log(' Remove the app from the process list :');
console.log(' $ pm2 delete api');
console.log('');
console.log(' Kill daemon pm2 :');
console.log(' $ pm2 kill');
console.log('');
console.log(' Update pm2 :');
console.log(' $ npm install pm2@latest -g ; pm2 update');
console.log('');
console.log(' More examples in https://github.com/Unitech/pm2#usagefeatures');
console.log('');
console.log(' Deployment help:');
console.log('');
console.log(' $ pm2 deploy help');
console.log('');
console.log('');
});
function displayUsage() {
console.log('usage: pm2 [options] <command>')
console.log('');
console.log('pm2 -h, --help all available commands and options');
console.log('pm2 examples display pm2 usage examples');
console.log('pm2 <command> -h help on a specific command');
console.log('');
console.log('Access pm2 files in ~/.pm2');
}
function displayExamples() {
console.log('- Start and add a process to the pm2 process list:')
console.log('');
console.log(chalk.cyan(' $ pm2 start app.js --name app'));
console.log('');
console.log('- Show the process list:');
console.log('');
console.log(chalk.cyan(' $ pm2 ls'));
console.log('');
console.log('- Stop and delete a process from the pm2 process list:');
console.log('');
console.log(chalk.cyan(' $ pm2 delete app'));
console.log('');
console.log('- Stop, start and restart a process from the process list:');
console.log('');
console.log(chalk.cyan(' $ pm2 stop app'));
console.log(chalk.cyan(' $ pm2 start app'));
console.log(chalk.cyan(' $ pm2 restart app'));
console.log('');
console.log('- Clusterize an app to all CPU cores available:');
console.log('');
console.log(chalk.cyan(' $ pm2 start -i max'));
console.log('');
console.log('- Update pm2 :');
console.log('');
console.log(chalk.cyan(' $ npm install pm2 -g && pm2 update'));
console.log('');
console.log('- Install pm2 auto completion:')
console.log('');
console.log(chalk.cyan(' $ pm2 completion install'))
console.log('');
console.log('Check the full documentation on https://pm2.io/doc');
console.log('');
}
if (process.argv.indexOf('-s') > -1) {
for(var key in console){
@ -155,7 +167,7 @@ function checkCompletion(){
return data.short;
}), data);
// array containing commands after which process name should be listed
var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'gracefulReload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show'];
var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show'];
if (cmdProcess.indexOf(data.prev) > -1) {
pm2.list(function(err, list){
@ -253,7 +265,7 @@ function patchCommanderArg(cmd) {
//
// Start command
//
commander.command('start <file|json|stdin|app_name|pm_id...>')
commander.command('start <name|file|ecosystem|id...>')
.option('--watch', 'Watch folder for changes')
.option('--fresh', 'Rebuild Dockerfile')
.option('--daemon', 'Run container in Daemon mode (debug purposes)')
@ -280,6 +292,9 @@ commander.command('start <file|json|stdin|app_name|pm_id...>')
else {
// Commander.js patch
cmd = patchCommanderArg(cmd);
if (cmd.length === 0) {
cmd = [cst.APP_CONF_DEFAULT_FILE];
}
async.forEachLimit(cmd, 1, function(script, next) {
pm2.start(script, commander, next);
}, function(err) {
@ -329,7 +344,7 @@ commander.command('startOrGracefulReload <json>')
//
commander.command('stop <id|name|all|json|stdin...>')
.option('--watch', 'Stop watching folder for changes')
.description('stop a process (to start it again, do pm2 restart <app>)')
.description('stop a process')
.action(function(param) {
async.forEachLimit(param, 1, function(script, next) {
pm2.stop(script, next);
@ -390,21 +405,19 @@ commander.command('reload <name|all>')
pm2.reload(pm2_id, commander);
});
//
// Reload process(es)
//
commander.command('gracefulReload <name|all>')
.description('gracefully reload a process. Send a "shutdown" message to close all connections.')
.action(function(pm2_id) {
pm2.gracefulReload(pm2_id, commander);
});
commander.command('id <name>')
.description('get process id by name')
.action(function(name) {
pm2.getProcessIdByName(name);
});
// Inspect a process
commander.command('inspect <name>')
.description('inspect a process')
.action(function(cmd) {
pm2.inspect(cmd, commander);
});
//
// Stop and delete a process by name from database
//
@ -464,11 +477,11 @@ commander.command('update')
/**
* Module specifics
*/
commander.command('install [module|git:// url|json]')
commander.command('install <module|git:// url>')
.alias('module:install')
.option('--v1', 'install module in v1 manner (do not use it)')
.option('--safe [time]', 'keep module backup, if new module fail = restore with previous')
.description('install or update a module (or a set of modules) and run it forever')
.description('install or update a module and run it forever')
.action(function(plugin_name, opts) {
if (opts.v1)
commander.v1 = true;
@ -553,41 +566,41 @@ commander.command('report')
commander.command('link [secret] [public] [name]')
.alias('interact')
.option('--info-node [url]', 'set url info node')
.description('linking action to keymetrics.io - command can be stop|info|delete|restart')
.description('link with the pm2 monitoring dashboard')
.action(pm2._pre_interact.bind(pm2));
commander.command('unlink')
.description('linking action to keymetrics.io - command can be stop|info|delete|restart')
.description('unlink with the pm2 monitoring dashboard')
.action(function() {
pm2.unlink();
});
commander.command('unmonitor [name]')
.description('unmonitor target process')
.action(function(name) {
pm2.monitorState('unmonitor', name);
});
commander.command('monitor [name]')
.description('monitor target process')
.action(function(name) {
pm2.monitorState('monitor', name);
});
commander.command('unmonitor [name]')
.description('unmonitor target process')
.action(function(name) {
pm2.monitorState('unmonitor', name);
});
commander.command('open')
.description('open dashboard in browser')
.description('open the pm2 monitoring dashboard')
.action(function(name) {
pm2.openDashboard();
});
commander.command('register')
.description('create an account on keymetrics')
.description('register on pm2 monitoring')
.action(function(name) {
pm2.registerToKM();
});
commander.command('login')
.description('login to keymetrics and link current PM2')
.description('use login to link with the pm2 monitoring dashboard')
.action(function(name) {
pm2.loginToKM();
});
@ -612,6 +625,15 @@ commander.command('dump')
pm2.dump();
}));
//
// Delete dump file
//
commander.command('cleardump')
.description('Create empty dump file')
.action(failOnUnknown(function() {
pm2.clearDump();
}));
//
// Save processes to file
//
@ -645,7 +667,7 @@ commander.command('resurrect')
// Set pm2 to startup
//
commander.command('unstartup [platform]')
.description('disable and clear auto startup - [platform]=systemd,upstart,launchd,rcd')
.description('disable the pm2 startup hook')
.action(function(platform) {
pm2.uninstallStartup(platform, commander);
});
@ -654,7 +676,7 @@ commander.command('unstartup [platform]')
// Set pm2 to startup
//
commander.command('startup [platform]')
.description('setup script for pm2 at boot - [platform]=systemd,upstart,launchd,rcd')
.description('enable the pm2 startup hook')
.action(function(platform) {
pm2.startup(platform, commander);
});
@ -891,15 +913,6 @@ commander.command('backward <name>')
pm2.backward(pm2_name);
});
//
// Force PM2 to trigger garbage collection
//
commander.command('gc')
.description('force PM2 to trigger garbage collection')
.action(function() {
pm2.forceGc();
});
//
// Perform a deep update of PM2
//
@ -919,13 +932,21 @@ commander.command('serve [path] [port]')
pm2.serve(path, port, commander);
});
commander.command('examples')
.description('display pm2 usage examples')
.action(() => {
console.log(cst.PREFIX_MSG + chalk.grey('pm2 usage examples:\n'));
displayExamples();
process.exit(cst.SUCCESS_EXIT);
})
//
// Catch all
//
commander.command('*')
.action(function() {
console.log(cst.PREFIX_MSG + '\nCommand not found');
commander.outputHelp();
console.log(cst.PREFIX_MSG + 'Command not found\n');
displayUsage();
// Check if it does not forget to close fds from RPC
process.exit(cst.ERROR_EXIT);
});
@ -935,7 +956,7 @@ commander.command('*')
//
if (process.argv.length == 2) {
commander.parse(process.argv);
commander.outputHelp();
displayUsage();
// Check if it does not forget to close fds from RPC
process.exit(cst.ERROR_EXIT);
}

View File

@ -28,7 +28,7 @@ var csts = {
TEMPLATE_FOLDER : p.join(__dirname, 'lib/templates'),
APP_CONF_DEFAULT_FILE : 'ecosystem.json',
APP_CONF_DEFAULT_FILE : 'ecosystem.config.js',
APP_CONF_TPL : 'ecosystem.tpl',
APP_CONF_TPL_SIMPLE : 'ecosystem-simple.tpl',
SAMPLE_CONF_FILE : 'sample-conf.js',

View File

@ -2,7 +2,7 @@
/*
* Example of graceful exit
*
* $ pm2 gracefulReload all
* $ pm2 reload all
*/
process.on('message', function(msg) {

View File

@ -399,33 +399,6 @@ API.prototype.update = function(cb) {
return false;
};
/**
* Graceful Reload an application
*
* @param {String} process_name Application Name or All
* @param {Object} opts Options
* @param {Function} cb Callback
*/
API.prototype.gracefulReload = function(process_name, opts, cb) {
var that = this;
if (typeof(opts) == "function") {
cb = opts;
opts = {};
}
//Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Warning gracefulReload will be soon deprecated'));
//Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Use http://pm2.keymetrics.io/docs/usage/signals-clean-restart/ instead'));
if (Common.isConfigFile(process_name))
that._startJson(process_name, commander, 'softReloadProcessId');
else {
if (opts && !opts.updateEnv)
Common.printOut(IMMUTABLE_MSG);
that._operate('softReloadProcessId', process_name, opts, cb);
}
};
/**
* Reload an application
*

3194
lib/API.js

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@ var fs = require('fs');
var fmt = require('../tools/fmt.js');
var moment = require('moment');
var pkg = require('../../package.json');
const semver = require('semver');
module.exports = function(CLI) {
@ -38,7 +39,6 @@ module.exports = function(CLI) {
*/
CLI.prototype.report = function() {
var that = this;
var semver = require('semver');
function reporting(cb) {
@ -639,4 +639,27 @@ module.exports = function(CLI) {
launchMonitor();
};
CLI.prototype.inspect = function(app_name, cb) {
const that = this;
if(semver.satisfies(process.versions.node, '>= 8.0.0')) {
this.trigger(app_name, 'internal:inspect', function (err, res) {
if(res && res[0]) {
if (res[0].data.return === '') {
Common.printOut(`Inspect disabled on ${app_name}`);
} else {
Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`);
}
} else {
Common.printOut(`Unable to activate inspect mode on ${app_name} !!!`);
}
that.exitCli(cst.SUCCESS_EXIT);
});
} else {
Common.printOut('Inspect is available for node version >=8.x !');
that.exitCli(cst.SUCCESS_EXIT);
}
};
};

View File

@ -6,6 +6,7 @@
var shelljs = require('shelljs');
var path = require('path');
var fs = require('fs');
var os = require('os');
var async = require('async');
var p = path;
var readline = require('readline');
@ -47,7 +48,7 @@ var KNOWN_MODULES = {
* - Generate sample module via pm2 module:generate <module_name>
*/
Modularizer.install = function (CLI, moduleName, opts, cb) {
// if user want to install module from ecosystem.json file
// if user want to install module from ecosystem.config.js 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;
@ -185,7 +186,7 @@ Modularizer.installModule = function(CLI, module_name, opts, cb) {
var install_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name);
mkdirp(install_path, function() {
process.chdir(process.env.HOME);
process.chdir(os.homedir());
var install_instance = spawn(cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error', '--prefix', install_path ], {
stdio : 'inherit',

View File

@ -7,6 +7,7 @@ var debug = require('debug')('pm2:cli:startup');
var chalk = require('chalk');
var path = require('path');
var fs = require('fs');
const fsExtra = require('fs-extra');
var async = require('async');
var exec = require('child_process').exec;
var Common = require('../Common.js');
@ -371,13 +372,32 @@ module.exports = function(CLI) {
* @return
*/
function fin(err) {
// try to fix issues with empty dump file
// like #3485
if (env_arr.length === 0) {
// fix : if no dump file, no process, only module and after pm2 update
if (!fs.existsSync(cst.DUMP_FILE_PATH)) {
that.clearDump(function(){});
}
// if no process in list don't modify dump file
// process list should not be empty
if(cb) {
return cb(null, {success: true});
} else {
Common.printOut(cst.PREFIX_MSG + 'Nothing to save !!!');
Common.printOut(cst.PREFIX_MSG + 'In this case we keep old dump file. To clear dump file you can delete it manually !');
that.exitCli(cst.SUCCESS_EXIT);
return;
}
}
// Back up dump file
try {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
}
fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
}
} catch (e) {
console.error(e.stack || e);
@ -390,8 +410,13 @@ module.exports = function(CLI) {
} catch (e) {
console.error(e.stack || e);
try {
fs.unlinkSync(cst.DUMP_FILE_PATH);
// try to backup file
if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fsExtra.copySync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH);
}
} catch (e) {
// don't keep broken file
fs.unlinkSync(cst.DUMP_FILE_PATH);
console.error(e.stack || e);
}
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to save dump file in %s', cst.DUMP_FILE_PATH);
@ -415,6 +440,21 @@ module.exports = function(CLI) {
});
};
/**
* Remove DUMP_FILE_PATH file and DUMP_BACKUP_FILE_PATH file
* @method dump
* @param {} cb
* @return
*/
CLI.prototype.clearDump = function(cb) {
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify([]));
if(cb && typeof cb === 'function') return cb();
Common.printOut(cst.PREFIX_MSG + 'Successfully created %s', cst.DUMP_FILE_PATH);
return this.exitCli(cst.SUCCESS_EXIT);
};
/**
* Resurrect processes
* @method resurrect

View File

@ -21,11 +21,11 @@ module.exports = function(CLI) {
printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
that.Client.getProcessByName(process_name, function(err, processes) {
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (processes.length === 0) {
printError('No processes with this name: %s', process_name);
return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT);
if (err || processes.length === 0) {
printError('No processes with this name or id : %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
@ -82,11 +82,11 @@ module.exports = function(CLI) {
printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
that.Client.getProcessByName(process_name, function(err, processes) {
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (processes.length === 0) {
printError('No processes with this name: %s', process_name);
return cb ? cb({msg:'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
if (err || processes.length === 0) {
printError('No processes with this name or id : %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
@ -138,14 +138,16 @@ module.exports = function(CLI) {
var that = this;
printOut(cst.PREFIX_MSG + 'Downgrading to previous commit repository for process name %s', process_name);
that.Client.getProcessByName(process_name, function(err, processes) {
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (processes.length === 0) {
printError('No processes with this name: %s', process_name);
return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT);
if (err || processes.length === 0) {
printError('No processes with this name or id : %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
// in case user searched by id/pid
process_name = proc.name;
if (proc.pm2_env.versioning === undefined ||
proc.pm2_env.versioning === null)
@ -194,14 +196,16 @@ module.exports = function(CLI) {
var that = this;
printOut(cst.PREFIX_MSG + 'Updating to next commit repository for process name %s', process_name);
that.Client.getProcessByName(process_name, function(err, processes) {
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (processes.length === 0) {
printError('No processes with this name: %s', process_name);
return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT);
if (err || processes.length === 0) {
printError('No processes with this name or id: %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
// in case user searched by id/pid
process_name = proc.name;
if (proc.pm2_env.versioning) {
vizion.next({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) {
if (err !== null)
@ -366,16 +370,6 @@ module.exports = function(CLI) {
this._pull({process_name: process_name, action: 'reload'}, cb);
};
/**
* CLI method for updating a repository
* @method pullAndGracefulReload
* @param {string} process_name name of processes to pull
* @return
*/
CLI.prototype.pullAndGracefulReload = function (process_name, cb) {
this._pull({process_name: process_name, action: 'gracefulReload'}, cb);
};
/**
* CLI method for updating a repository to a specific commit id
* @method pullCommitId

View File

@ -2,23 +2,87 @@
"script": {
"type": "string",
"require": true,
"alias" : "exec"
"alias" : "exec",
"docDescription": "Path of the script to launch, required field"
},
"name": {
"type": "string",
"docDefault": "Script filename without the extension (app for app.js)",
"docDescription": "Process name in the process list"
},
"cwd": {
"type": "string",
"docDefault": "CWD of the current environment (from your shell)",
"docDescription": "Current working directory to start the process with"
},
"args": {
"type": [
"array",
"string"
]
],
"docDescription": "Arguments to pass to the script"
},
"exec_interpreter": {
"type": "string",
"alias": "interpreter",
"docDefault": "node",
"docDescription": "Interpreter absolute path"
},
"node_args": {
"type": [
"array",
"string"
],
"alias": ["interpreterArgs", "interpreter_args"]
"alias": ["interpreterArgs", "interpreter_args"],
"docDescription": "Arguments to pass to the interpreter"
},
"name": {
"type": "string"
"out_file": {
"type": "string",
"alias": ["out", "output", "out_log"],
"docDefault": "~/.pm2/logs/<app_name>-out.log",
"docDescription": "File path for stdout (each line is appended to this file)"
},
"error_file": {
"type": "string",
"alias": ["error", "err", "err_file", "err_log"],
"docDefault": "~/.pm2/logs/<app_name>-error.err",
"docDescription": "File path for stderr (each line is appended to this file)"
},
"log_file": {
"type": [
"boolean",
"string"
],
"alias": "log",
"docDefault": "/dev/null",
"docDescription": "File path for combined stdout and stderr (each line is appended to this file)"
},
"disable_logs": {
"type": "boolean",
"docDefault": false,
"docDescription": "Disable all logs storage"
},
"log_type": {
"type": "string",
"docDescription": "Define a specific log output type, possible value: json"
},
"log_date_format": {
"type": "string",
"docDescription": "Format for log timestamps in moment.js format (eg YYYY-MM-DD HH:mm Z)"
},
"env": {
"type": [
"object",
"string"
],
"docDescription": "Specify environment variables to be injected"
},
"^env_\\S*$": {
"type": [
"object",
"string"
],
"docDescription": "Specify environment variables to be injected when using --env <env_name>"
},
"max_memory_restart": {
"type": [
@ -27,124 +91,91 @@
],
"regex": "^\\d+(G|M|K)?$",
"ext_type": "sbyte",
"desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)"
},
"uid" : {
"type" : "string"
},
"gid" : {
"type" : "string"
},
"restart_delay": {
"type" : "number"
},
"source_map_support" : {
"type": "boolean"
},
"wait_ready" : {
"type": "boolean"
},
"disable_source_map_support" : {
"type": "boolean"
},
"instances": {
"type": "number"
},
"kill_timeout": {
"type": "number"
},
"listen_timeout": {
"type": "number"
},
"port": {
"type": "number"
},
"log_file": {
"type": [
"boolean",
"string"
],
"alias": "log"
},
"error_file": {
"type": "string",
"alias": ["error", "err", "err_file", "err_log"]
},
"log_type": {
"type": "string"
},
"out_file": {
"type": "string",
"alias": ["output", "out", "out_log"]
"desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)",
"docDescription": "Restart the app if an amount of memory is exceeded (format: /[0-9](K&#124;M&#124;G)?/ K for KB, 'M' for MB, 'G' for GB, default to B)"
},
"pid_file": {
"type": "string",
"alias": "pid"
"alias": "pid",
"docDefault": "~/.pm2/pids/app_name-id.pid",
"docDescription": "File path where the pid of the started process is written by pm2"
},
"restart_delay": {
"type" : "number",
"docDefault": 0,
"docDescription": "Time in ms to wait before restarting a crashing app"
},
"source_map_support": {
"type": "boolean",
"docDefault": true,
"docDescription": "Enable or disable the source map support"
},
"disable_source_map_support": {
"type": "boolean",
"docDefault": false,
"docDescription": "Enable or disable the source map support"
},
"wait_ready": {
"type": "boolean",
"docDefault": false,
"docDescription": "Make the process wait for a process.send('ready')"
},
"instances": {
"type": "number",
"docDefault": 1,
"docDescription": "Number of instances to be started in cluster mode"
},
"kill_timeout": {
"type": "number",
"docDefault": 1600,
"docDescription": "Time in ms before sending the final SIGKILL signal after SIGINT"
},
"listen_timeout": {
"type": "number",
"docDescription": "Time in ms before forcing a reload if app is still not listening/has still note sent ready"
},
"cron_restart": {
"type": "string",
"alias": "cron"
},
"cwd": {
"type": "string"
"alias": "cron",
"docDescription": "A cron pattern to restart your app"
},
"merge_logs": {
"type": "boolean",
"alias" : "combine_logs"
"alias" : "combine_logs",
"docDefault": false,
"docDescription": "In cluster mode, merge each type of logs into a single file (instead of having one for each cluster)"
},
"vizion" : {
"vizion": {
"type": "boolean",
"default" : true
"default" : true,
"docDefault" : "True",
"docDescription": "Enable or disable the versioning metadatas (vizion library)"
},
"pmx" : {
"autorestart": {
"type": "boolean",
"default" : true
},
"automation" : {
"type": "boolean",
"default" : true
},
"autorestart" : {
"type": "boolean",
"default" : true
},
"treekill" : {
"type": "boolean",
"default" : true
"default": true,
"docDefault": "True",
"docDescription": "Enable or disable auto restart after process failure"
},
"watch": {
"type": [
"boolean",
"array",
"string"
]
],
"docDefault": false,
"docDescription": "Enable or disable the watch mode"
},
"ignore_watch": {
"type": [
"array",
"string"
]
],
"docDescription": "List of paths to ignore (regex)"
},
"watch_options": {
"type": "object"
},
"env": {
"type": [
"object",
"string"
]
},
"^env_\\S*$": {
"type": [
"object",
"string"
]
},
"disable_logs" : {
"type": "boolean"
},
"log_date_format": {
"type": "string"
"type": "object",
"docDescription": "Object that will be used as an options with chokidar (refer to chokidar documentation)"
},
"min_uptime": {
"type": [
@ -154,43 +185,51 @@
"regex": "^\\d+(h|m|s)?$",
"desc": "it should be a NUMBER - milliseconds, \"[NUMBER]h\"(hours), \"[NUMBER]m\"(minutes) or \"[NUMBER]s\"(seconds)",
"min": 100,
"ext_type": "stime"
"ext_type": "stime",
"docDefault": 1000,
"docDescription": "Minimum uptime of the app to be considered started (format is /[0-9]+(h&#124;m&#124;s)?/, for hours, minutes, seconds, docDefault to ms)"
},
"max_restarts": {
"type": "number",
"min": 0
"min": 0,
"docDefault": 16,
"docDescription": "Number of times a script is restarted when it exits in less than min_uptime"
},
"exec_mode": {
"type": "string",
"regex": "^(cluster|fork)(_mode)?$",
"alias": "executeCommand",
"desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only"
},
"exec_interpreter": {
"type": "string",
"alias": "interpreter"
},
"write": {
"type": "boolean"
"desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only",
"docDefault": "fork",
"docDescription": "Set the execution mode, possible values: fork&#124;cluster"
},
"force": {
"type": "boolean"
"type": "boolean",
"docDefault": false,
"docDescription": "Start a script even if it is already running (only the script path is considered)"
},
"append_env_to_name": {
"type": "boolean"
"type": "boolean",
"docDefault": false,
"docDescription": "Append the environment name to the app name"
},
"post_update": {
"type": "array"
},
"disable_trace": {
"type": [
"boolean"
]
"type": "array",
"docDescription": "List of commands executed after a pull/upgrade operation performed from Keymetrics dashboard"
},
"trace": {
"type": [
"boolean"
]
],
"docDefault": false,
"docDescription": "Enable or disable the transaction tracing"
},
"disable_trace": {
"type": [
"boolean"
],
"docDefault": true,
"docDescription": "Enable or disable the transaction tracing"
},
"v8": {
"type": [
@ -208,18 +247,58 @@
]
},
"increment_var": {
"type": "string"
"type": "string",
"docDescription": "Specify the name of an environment variable to inject which increments for each cluster"
},
"instance_var": {
"type": "string",
"default" : "NODE_APP_INSTANCE"
},
"default": "NODE_APP_INSTANCE",
"docDefault": "NODE_APP_INSTANCE",
"docDescription": "Rename the NODE_APP_INSTANCE environment variable"
},
"pmx": {
"type": "boolean",
"default": true,
"docDefault": "True",
"docDescription": "Enable or disable pmx wrapping"
},
"automation": {
"type": "boolean",
"default": true,
"docDefault": "True",
"docDescription": "Enable or disable pmx wrapping"
},
"treekill": {
"type": "boolean",
"default": true,
"docDefault": "True",
"docDescription": "Only kill the main process, not detached children"
},
"port": {
"type": "number",
"docDescription": "Shortcut to inject a PORT environment variable"
},
"uid": {
"type" : "string",
"docDefault": "Current user uid",
"docDescription": "Set user id"
},
"gid": {
"type" : "string",
"docDefault": "Current user gid",
"docDescription": "Set group id"
},
"windowsHide": {
"type": "boolean",
"default" : true
"docDefault": "True",
"docDescription": "Enable or disable the Windows popup when starting an app",
"default": true
},
"kill_retry_time": {
"type": "number",
"default" : 100
},
"write": {
"type": "boolean"
}
}

View File

@ -717,3 +717,25 @@ Client.prototype.getProcessByName = function(name, cb) {
return cb(null, found_proc);
});
};
Client.prototype.getProcessByNameOrId = function (nameOrId, cb) {
var foundProc = [];
this.executeRemote('getMonitorData', {}, function (err, list) {
if (err) {
Common.printError('Error retrieving process list: ' + err);
return cb(err);
}
list.forEach(function (proc) {
if (proc.pm2_env.name === nameOrId ||
proc.pm2_env.pm_exec_path === path.resolve(nameOrId) ||
proc.pid === parseInt(nameOrId) ||
proc.pm2_env.pm_id === parseInt(nameOrId)) {
foundProc.push(proc);
}
});
return cb(null, foundProc);
});
};

View File

@ -247,20 +247,22 @@ Common.prepareAppConf = function(opts, app) {
* @param {string} filename
* @return {mixed} null if not conf file, json or yaml if conf
*/
Common.isConfigFile = function(filename) {
if (typeof(filename) != 'string')
Common.isConfigFile = function (filename) {
if (typeof (filename) !== 'string')
return null;
if (filename.indexOf('.json') != -1)
if (filename.indexOf('.json') !== -1)
return 'json';
if (filename.indexOf('.yml') > -1 || filename.indexOf('.yaml') > -1)
return 'yaml';
if (filename.indexOf('.config.js') != -1)
if (filename.indexOf('.config.js') !== -1)
return 'js';
if (filename.indexOf('.config.mjs') !== -1)
return 'mjs';
return null;
};
/**
* Parses a config file like ecosystem.json. Supported formats: JS, JSON, JSON5, YAML.
* Parses a config file like ecosystem.config.js. Supported formats: JS, JSON, JSON5, YAML.
* @param {string} confString contents of the config file
* @param {string} filename path to the config file
* @return {Object} config object
@ -288,7 +290,7 @@ Common.parseConfig = function(confObj, filename) {
filename.indexOf('.yaml') > -1) {
return yamljs.parse(confObj.toString());
}
else if (filename.indexOf('.config.js') > -1) {
else if (filename.indexOf('.config.js') > -1 || filename.indexOf('.config.mjs') > -1) {
var confPath = require.resolve(path.resolve(filename));
delete require.cache[confPath];
return require(confPath);

View File

@ -153,7 +153,7 @@ Daemon.prototype.innerStart = function(cb) {
var profiler;
try {
profiler = require('v8-profiler');
profiler = require('v8-profiler-node8');
} catch(e) {
profiler = null;
}
@ -231,7 +231,6 @@ Daemon.prototype.innerStart = function(cb) {
notifyByProcessId : God.notifyByProcessId,
notifyKillPM2 : God.notifyKillPM2,
forceGc : God.forceGc,
monitor : God.monitor,
unmonitor : God.unmonitor,

View File

@ -12,6 +12,7 @@
*/
var fs = require('fs');
const fsExtra = require('fs-extra');
var path = require('path');
var async = require('async');
var os = require('os');
@ -137,13 +138,25 @@ module.exports = function(God) {
}
function fin(err) {
// try to fix issues with empty dump file
// like #3485
if (process_list.length === 0) {
// fix : if no dump file, no process, only module and after pm2 update
if (!fs.existsSync(cst.DUMP_FILE_PATH)) {
that.clearDump(function(){});
}
// if no process in list don't modify dump file
// process list should not be empty
return cb(null, {success:true, process_list: process_list});
}
// Back up dump file
try {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH);
}
fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH);
}
} catch (e) {
console.error(e.stack || e);
@ -155,8 +168,13 @@ module.exports = function(God) {
} catch (e) {
console.error(e.stack || e);
try {
fs.unlinkSync(cst.DUMP_FILE_PATH);
// try to backup file
if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fsExtra.copySync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH);
}
} catch (e) {
// don't keep broken file
fs.unlinkSync(cst.DUMP_FILE_PATH);
console.error(e.stack || e);
}
}

View File

@ -247,21 +247,4 @@ module.exports = function(God) {
pm2_env.unstable_restarts = 0;
};
/**
* Description
* @method forcegc
* @return
*/
God.forceGc = function(opts, cb) {
if (global.gc) {
global.gc();
debug('Garbage collection triggered successfully');
if (cb) cb(null, {success: true});
}
else {
debug('Garbage collection failed');
if (cb) cb(null, {success: false});
}
};
};

View File

@ -174,7 +174,7 @@ function hardReload(God, id, wait_msg, cb) {
module.exports = function(God) {
/**
* GracefulReload
* Reload
* @method softReloadProcessId
* @param {} id
* @param {} cb

View File

@ -21,7 +21,6 @@ var Password = require('../Password.js');
var PM2_REMOTE_METHOD_ALLOWED = {
'restart' : {},
'reload' : {},
'gracefulReload' : {},
'reset' : {},
'scale' : {},

View File

@ -30,15 +30,7 @@ delete process.env.pm2_env;
(function ProcessContainer() {
var fs = require('fs');
if (process.env.pmx !== 'false') {
require('pmx').init({
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
});
}
require('./ProcessUtils').injectModules();
var stdFile = pm2_env.pm_log_path;
var outFile = pm2_env.pm_out_log_path;

View File

@ -1,18 +1,10 @@
/**
/**
* Copyright 2013 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
// Inject custom modules
if (process.env.pmx !== 'false') {
require('pmx').init({
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
});
}
require('./ProcessUtils').injectModules();
if (typeof(process.env.source_map_support) != "undefined" &&
process.env.source_map_support !== "false") {

29
lib/ProcessUtils.js Normal file
View File

@ -0,0 +1,29 @@
module.exports = {
injectModules: function() {
if (process.env.pmx !== 'false') {
const pmx = require('pmx');
pmx.init({
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
});
if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) {
var url = '';
pmx.action('internal:inspect', function(reply) {
const inspector = require('inspector');
if(url === '') {
inspector.open();
url = inspector.url();
} else {
inspector.close();
url = '';
}
reply(url);
});
}
}
}
};

View File

@ -215,7 +215,6 @@ Satan.remoteWrapper = function() {
killMe : God.killMe,
notifyKillPM2 : God.notifyKillPM2,
forceGc : God.forceGc,
findByFullPath : God.findByFullPath,

View File

@ -3,7 +3,7 @@
"preferGlobal": true,
"version": "2.10.1",
"engines": {
"node": ">=0.12"
"node": ">=4.0.0"
},
"directories": {
"bin": "./bin",
@ -161,19 +161,20 @@
"dependencies": {
"async": "^2.5",
"blessed": "^0.1.81",
"chalk": "^1.1",
"chokidar": "^2",
"chalk": "^2.3.1",
"chokidar": "^2.0.2",
"cli-table-redemption": "^1.0.0",
"commander": "2.13.0",
"commander": "2.14.1",
"cron": "^1.3",
"debug": "^3.0",
"eventemitter2": "1.0.5",
"eventemitter2": "5.0.1",
"fclone": "1.0.11",
"fs-extra": "^5.0.0",
"mkdirp": "0.5.1",
"moment": "^2.19",
"needle": "^2.1.0",
"needle": "^2.2.0",
"nssocket": "0.6.0",
"pidusage": "^1.2.0",
"pidusage": "^2.0.0",
"pm2-axon": "3.1.0",
"pm2-axon-rpc": "0.5.0",
"pm2-deploy": "^0.3.9",
@ -181,7 +182,7 @@
"pmx": "^1.6",
"promptly": "2.2.0",
"semver": "^5.3",
"shelljs": "0.7.8",
"shelljs": "0.8.1",
"source-map-support": "^0.5",
"sprintf-js": "1.1.1",
"v8-compile-cache": "^1.1.0",
@ -190,7 +191,7 @@
},
"devDependencies": {
"mocha": "^3.5",
"should": "^11"
"should": "^13"
},
"optionalDependencies": {
"gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz"

View File

@ -58,14 +58,10 @@ $pm2 reload app-config-update/echo.js --node-args="--harmony"
$pm2 prettylist | grep "node_args: \[ '--harmony' \]"
spec "Should application have one node argument"
$pm2 gracefulReload app-config-update/echo.js --node-args="--harmony"
$pm2 prettylist | grep "node_args: \[ '--harmony' \]"
spec "Should application have two node arguments"
$pm2 prettylist | grep "node_args"
spec "Should have found parameter"
# Now set node-args to null
$pm2 gracefulReload app-config-update/echo.js --node-args=null
$pm2 reload app-config-update/echo.js --node-args=null
# Should not find node_args anymore
$pm2 prettylist | grep "node_args"
ispec "Should have deleted cli parameter when passing null"
@ -74,8 +70,3 @@ $pm2 reload echo --name="new-name"
$pm2 reset all
$pm2 restart new-name
should 'should reload processes with new name' 'restart_time: 1' 1
$pm2 gracefulReload new-name --name="new-name-2"
$pm2 reset all
$pm2 restart new-name-2
should 'should graceful reload processes with new name' 'restart_time: 1' 1

View File

@ -1,35 +0,0 @@
#!/usr/bin/env bash
SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/include.sh"
cd $file_path
echo "################## GRACEFUL RELOAD ###################"
###############
echo "Launching"
$pm2 start graceful-exit.js -i 4 --name="graceful" -o "grace.log" -e "grace-err.log"
should 'should start processes' 'online' 4
OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"`
cat /dev/null > $OUT_LOG
#### Graceful reload all
$pm2 gracefulReload all
OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l`
[ $OUT -eq 1 ] || fail "Process not restarted gracefuly"
success "Process restarted gracefuly"
cat /dev/null > $OUT_LOG
#### Graceful reload name
$pm2 gracefulReload graceful
OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l`
[ $OUT -eq 1 ] || fail "Process not restarted gracefuly"
success "Process restarted gracefuly"

View File

@ -1,28 +0,0 @@
#!/usr/bin/env bash
SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/include.sh"
cd $file_path
echo "################## GRACEFUL RELOAD 2 ###################"
echo "Launching"
$pm2 start graceful-exit-no-listen.js -i 2 --name="graceful2" -o "grace2.log" -e "grace-err2.log"
should 'should start processes' 'online' 2
OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"`
cat /dev/null > $OUT_LOG
#### Graceful reload name
$pm2 gracefulReload graceful2
echo "PATH: $OUT_LOG"
TEXT=$(cat $OUT_LOG)
echo "TEXT: $TEXT"
OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l`
[ $OUT -eq 1 ] || fail "Non-listening process not restarted gracefuly"
success "Non-listening process restarted gracefuly"

View File

@ -1,22 +0,0 @@
#!/usr/bin/env bash
SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/include.sh"
cd $file_path
echo "################## GRACEFUL RELOAD 3 ###################"
echo "Launching"
$pm2 start graceful-exit-send.js -i 2 --name="graceful3" -o "grace3.log" -e "grace-err3.log"
should 'should start processes' 'online' 2
OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"`
cat /dev/null > $OUT_LOG
#### Graceful reload name
$pm2 gracefulReload graceful3
OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l`
[ $OUT -eq 1 ] || fail "Process that sends 'online' not restarted gracefuly"
success "Process that sends 'online' restarted gracefuly"

View File

@ -36,18 +36,13 @@ sleep 1
should 'should reload processes' 'online' 6
should 'should all script been restarted one time' 'restart_time: 2' 6
$pm2 gracefulReload all.json
sleep 1
should 'should graceful reload processes' 'online' 6
should 'should all script been restarted one time' 'restart_time: 3' 6
##
## Smart restart
##
$pm2 start all.json
sleep 1
should 'should smart restart processes' 'online' 6
should 'should all script been restarted one time' 'restart_time: 4' 6
should 'should all script been restarted one time' 'restart_time: 3' 6
$pm2 stop all.json
sleep 1

View File

@ -50,8 +50,6 @@ $pm2 restart delayed_exit.js
should 'should restart processes' 'restart_time: 1' 2
$pm2 reload delayed_exit.js
should 'should restart processes' 'restart_time: 2' 2
$pm2 gracefulReload delayed_exit.js
should 'should restart processes' 'restart_time: 3' 2
$pm2 kill
$pm2 start child.js -i 4

View File

@ -2,7 +2,7 @@
/*
* Example of graceful exit that does not listen
*
* $ pm2 gracefulReload all
* $ pm2 reload all
*/
process.on('message', function(msg) {

View File

@ -2,7 +2,7 @@
/*
* Example of graceful exit that does not listen but sends 'online'
*
* $ pm2 gracefulReload all
* $ pm2 reload all
*/
process.on('message', function(msg) {

View File

@ -2,7 +2,7 @@
/*
* Example of graceful exit
*
* $ pm2 gracefulReload all
* $ pm2 reload all
*/
process.on('message', function(msg) {

View File

@ -145,30 +145,6 @@ describe('REMOTE PM2 ACTIONS', function() {
});
});
it('should gracefulRELOAD', function(done) {
send_cmd.once('trigger:pm2:result', function(pck) {
/**
* Once remote command is finished...
*/
should(pck.ret.err).be.null();
pm2.list(function(err, ret) {
ret.forEach(function(proc) {
proc.pm2_env.restart_time.should.eql(3);
});
});
done();
});
send_cmd.emit('cmd', {
_type : 'trigger:pm2:action',
method_name : 'gracefulReload',
parameters : {name : 'child' }
});
});
it('should RESET metadata', function(done) {
send_cmd.once('trigger:pm2:result', function(pck) {
/**

View File

@ -81,12 +81,6 @@ bash ./test/bash/right-exit-code.sh
spec "Verification exit code"
bash ./test/bash/log-reload.sh
spec "Log reload"
bash ./test/bash/gracefulReload.sh
spec "gracefulReload system 1"
bash ./test/bash/gracefulReload2.sh
spec "gracefulReload system 2"
bash ./test/bash/gracefulReload3.sh
spec "gracefulReload system 3"
bash ./test/bash/misc.sh
spec "MISC features"
bash ./test/bash/fork.sh

View File

@ -18,7 +18,12 @@ describe('PM2 programmatic calls', function() {
});
after(function(done) {
pm2.kill(done);
pm2.delete('all', function(err, ret) {
// clean dump file
pm2.clearDump(function(err) {
pm2.kill(done);
});
});
});
before(function(done) {

View File

@ -162,21 +162,6 @@ describe('Signal kill (+delayed)', function() {
});
});
it('should graceful reload script', function(done) {
setTimeout(function() {
pm2.list(function(err, list) {
list[0].pm2_env.status.should.eql('online');
list[0].pm2_env.restart_time.should.eql(2);
done();
});
}, 1500);
pm2.gracefulReload('delayed-sigint', function(err, app) {
//done(err);
});
});
});
describe('with 4000ms via kill_timeout (json/cli option)', function() {