From b59610e5406b71da9cd0b88146edd0ba6a219700 Mon Sep 17 00:00:00 2001 From: Todd Wong Date: Fri, 12 Jan 2018 14:06:49 +0800 Subject: [PATCH 01/36] #2182 Get rid of annoying popups in Windows 10 --- lib/God.js | 1 + lib/God/ForkMode.js | 1 - lib/TreeKill.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/God.js b/lib/God.js index bf3bedda6..8df9b7f5a 100644 --- a/lib/God.js +++ b/lib/God.js @@ -31,6 +31,7 @@ var async = require('async'); * Override cluster module configuration */ cluster.setupMaster({ + windowsHide: true, exec : path.resolve(path.dirname(module.filename), 'ProcessContainer.js') }); diff --git a/lib/God/ForkMode.js b/lib/God/ForkMode.js index 870519962..3451cc6d2 100644 --- a/lib/God/ForkMode.js +++ b/lib/God/ForkMode.js @@ -93,7 +93,6 @@ module.exports = function ForkMode(God) { try { var cspr = spawn(command, args, { env : pm2_env, - detached : true, windowsHide: true, cwd : pm2_env.pm_cwd || process.cwd(), stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core diff --git a/lib/TreeKill.js b/lib/TreeKill.js index 329aab851..4365e2eac 100644 --- a/lib/TreeKill.js +++ b/lib/TreeKill.js @@ -14,7 +14,7 @@ module.exports = function (pid, signal, callback) { switch (process.platform) { case 'win32': - exec('taskkill /pid ' + pid + ' /T /F', callback); + exec('taskkill /pid ' + pid + ' /T /F', { windowsHide: true }, callback); break; case 'darwin': buildProcessTree(pid, tree, pidsToProcess, function (parentPid) { From 3dd044f712a1f81a89207be97ab786fa62c70954 Mon Sep 17 00:00:00 2001 From: Todd Wong Date: Sat, 13 Jan 2018 22:19:25 +0800 Subject: [PATCH 02/36] fixup! #2182 Get rid of annoying popups in Windows 10 --- lib/God/ForkMode.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/God/ForkMode.js b/lib/God/ForkMode.js index 3451cc6d2..870519962 100644 --- a/lib/God/ForkMode.js +++ b/lib/God/ForkMode.js @@ -93,6 +93,7 @@ module.exports = function ForkMode(God) { try { var cspr = spawn(command, args, { env : pm2_env, + detached : true, windowsHide: true, cwd : pm2_env.pm_cwd || process.cwd(), stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core From 0046301f6b973c4c7380aeaebd57715fd589abe9 Mon Sep 17 00:00:00 2001 From: Paul Rohja Lesellier Date: Tue, 23 Jan 2018 13:38:34 +0100 Subject: [PATCH 03/36] packaging: remove drone_build_number from version --- packager/build-deb-rpm.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packager/build-deb-rpm.sh b/packager/build-deb-rpm.sh index f05587900..d8a195f8a 100755 --- a/packager/build-deb-rpm.sh +++ b/packager/build-deb-rpm.sh @@ -17,7 +17,7 @@ echo "Cleaning PACKAGE_TMPDIR..." rm -rf $PACKAGE_TMPDIR PM2_VERSION=`node dist/bin/pm2 --version` -VERSION=$PM2_VERSION"-"$DRONE_BUILD_NUMBER +VERSION=$PM2_VERSION TARBALL_NAME=dist/pm2-v$PM2_VERSION.tar.gz OUTPUT_DIR=artifacts @@ -121,7 +121,7 @@ fpm --input-type dir --chdir $PACKAGE_TMPDIR \ --description '$(cat packager/debian/description)' \ --vendor 'Keymetrics ' \ --maintainer 'Alexandre Strzelewicz ' \ - --version $PM2_VERSION --iteration $DRONE_BUILD_NUMBER \ + --version $PM2_VERSION \ --after-install packager/rhel/postinst \ --before-remove packager/rhel/prerm \ --after-remove packager/rhel/postrm \ From 5793321377e16f92ad2294da0568e51569329d1a Mon Sep 17 00:00:00 2001 From: Paul Rohja Lesellier Date: Tue, 23 Jan 2018 13:44:05 +0100 Subject: [PATCH 04/36] packaging: remove env variable for apk build that prevented version detection --- .drone.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index e3ec8d34e..89a44e2de 100644 --- a/.drone.yml +++ b/.drone.yml @@ -20,7 +20,6 @@ pipeline: image: keymetrics/alpine-pm2-builder:latest environment: - AWS_REPO_BUCKET=alpine-apk.pm2.io - - PM2_TARGET_VERSION=2.7.2 secrets: ['apk_rsa_priv_key', 'apk_rsa_pub_key', 'aws_access_key_id', 'aws_secret_access_key'] when: event: tag From cb2957d82dd496b5df229ee150026216037240bb Mon Sep 17 00:00:00 2001 From: Paul Rohja Lesellier Date: Tue, 23 Jan 2018 13:48:16 +0100 Subject: [PATCH 05/36] packaging: add deb upload for ubuntu/trusty (14.04) --- packager/publish_deb_rpm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packager/publish_deb_rpm.sh b/packager/publish_deb_rpm.sh index 99ed4902a..911172124 100755 --- a/packager/publish_deb_rpm.sh +++ b/packager/publish_deb_rpm.sh @@ -2,7 +2,7 @@ REPOSITORY_NAME="keymetrics/pm2" -for OSDIST in 'ubuntu/xenial' 'ubuntu/yakkety' 'ubuntu/zesty' 'ubuntu/artful' 'debian/wheezy' 'debian/jessie' 'debian/stretch' 'debian/buster' 'raspbian/wheezy' 'raspbian/jessie' 'raspbian/stretch' 'raspbian/buster' +for OSDIST in 'ubuntu/trusty' 'ubuntu/xenial' 'ubuntu/yakkety' 'ubuntu/zesty' 'ubuntu/artful' 'debian/wheezy' 'debian/jessie' 'debian/stretch' 'debian/buster' 'raspbian/wheezy' 'raspbian/jessie' 'raspbian/stretch' 'raspbian/buster' do package_cloud push $REPOSITORY_NAME/$OSDIST `find -name "*.deb"` done From d11fc1291eedec23c028822e91c8b3d6b36b811a Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 23 Jan 2018 15:09:53 +0100 Subject: [PATCH 06/36] feat add changelog generation support --- .changelogrc | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 2 +- template.md | 13 +++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 .changelogrc create mode 100644 template.md diff --git a/.changelogrc b/.changelogrc new file mode 100644 index 000000000..67e6dcb29 --- /dev/null +++ b/.changelogrc @@ -0,0 +1,53 @@ +{ + "app_name": "", + "logo": "", + "intro": "", + "branch" : "master", + "repo_url": "https://github.com/Unitech/pm2", + "version_name" : "v2.9.2", + "tag": "2.9.1", + "file": "currentTagChangelog.md", + "template": "template.md", + "sections": [ + { + "title": "Bug Fixes", + "grep": "^fix" + }, + { + "title": "Features", + "grep": "^feat" + }, + { + "title": "Documentation", + "grep": "^docs" + }, + { + "title": "Breaking changes", + "grep": "BREAKING" + }, + { + "title": "Refactor", + "grep": "^refactor" + }, + { + "title": "Style", + "grep": "^style" + }, + { + "title": "Test", + "grep": "^test" + }, + { + "title": "Chore", + "grep": "^chore" + }, + { + "title": "Branchs merged", + "grep": "^Merge branch" + }, + { + "title" : "Pull requests merged", + "grep": "^Merge pull request" + } + ] +} diff --git a/.gitignore b/.gitignore index 7903de4bc..31e1bf66d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ /node_modules *.log -*.log *.pid test/child *.iml @@ -15,3 +14,4 @@ package-lock.json .DS_Store *.swp *.swo +currentTagChangelog.md diff --git a/template.md b/template.md new file mode 100644 index 000000000..b82e71d2c --- /dev/null +++ b/template.md @@ -0,0 +1,13 @@ +<% if(logo) { %>pm2 logo <% } %> +<% if(logo) { %># <%= title %> <% } %> +<% if(intro) { %><%= '\n' %><%= intro %><%= '\n' %><% } %> +<% if(version && (version.name || version.number)) { %>##<% if(version.name){%> <%= version.name %><% } %> <% if(version.date){ %>( <%= version.date %> )<% } %><%= '\n' %><% } %> +<% _.forEach(sections, function(section){ + if(section.commitsCount > 0) { %> +## <%= section.title %> +<% _.forEach(section.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %> +<% _.forEach(section.components, function(component){ %> - **<%= component.name %>** +<% _.forEach(component.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %> +<% }) %> +<% } %> +<% }) %> From 83bf98f3fba1f71b0ba2b0779a1931ff7a365181 Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 23 Jan 2018 15:19:44 +0100 Subject: [PATCH 07/36] refactor : rename template's file for changelog generation --- .changelogrc | 2 +- template.md => changelogTemplate.md | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename template.md => changelogTemplate.md (100%) diff --git a/.changelogrc b/.changelogrc index 67e6dcb29..52b406f96 100644 --- a/.changelogrc +++ b/.changelogrc @@ -7,7 +7,7 @@ "version_name" : "v2.9.2", "tag": "2.9.1", "file": "currentTagChangelog.md", - "template": "template.md", + "template": "changelogTemplate.md", "sections": [ { "title": "Bug Fixes", diff --git a/template.md b/changelogTemplate.md similarity index 100% rename from template.md rename to changelogTemplate.md From bc848299911ba5ffe79cac62816e5b2004f1edc0 Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 23 Jan 2018 16:03:22 +0100 Subject: [PATCH 08/36] chore : add perf and hotfix prefix and update contributing file --- .changelogrc | 8 ++++++++ CONTRIBUTING.md | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/.changelogrc b/.changelogrc index 52b406f96..e1a840525 100644 --- a/.changelogrc +++ b/.changelogrc @@ -13,6 +13,10 @@ "title": "Bug Fixes", "grep": "^fix" }, + { + "title": "Hot Fixes", + "grep": "^hotfix" + }, { "title": "Features", "grep": "^feat" @@ -29,6 +33,10 @@ "title": "Refactor", "grep": "^refactor" }, + { + "title": "Performance improvement", + "grep": "^perf" + }, { "title": "Style", "grep": "^style" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cc70eea70..83fa8beac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,29 @@ When you modify the Daemon (lib/Daemon.js, lib/God.js, lib/God/*, lib/Watcher.js $ pm2 update ``` +## 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 There are two tests type. Programmatic and Behavioral. From e8a2991591b6b793556466c377737fe7fc2a5f5c Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 24 Jan 2018 11:39:02 +0100 Subject: [PATCH 09/36] docs: add sendDataToProcessId into typescript definitions --- types/index.d.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/types/index.d.ts b/types/index.d.ts index b78d1fd27..dba5c2303 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -170,6 +170,14 @@ export function sendSignalToProcessName(signal:string|number, process: number|st */ export function startup(platform: Platform, errback: ErrResultCallback): void; +/** + * - 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 export interface Proc { From 86fe410098e5b502ace8f9ce482d8196658096e8 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Thu, 25 Jan 2018 22:24:49 +0100 Subject: [PATCH 10/36] .bithoundrc --- .bithoundrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bithoundrc b/.bithoundrc index e54a40fc5..94a26fe14 100644 --- a/.bithoundrc +++ b/.bithoundrc @@ -5,6 +5,6 @@ "**/examples/**" ], "critics": { - "lint": {"engine": "semistandard"} + "lint": {"engine": "eslint"} } } From 291b34951264b132341b14965eb8a8735c0f1a40 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Thu, 25 Jan 2018 22:32:48 +0100 Subject: [PATCH 11/36] upgrade chokidar + commander + needle --- package.json | 8 ++++---- test/mocha.opts | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6db86cc86..28cfed820 100644 --- a/package.json +++ b/package.json @@ -162,16 +162,16 @@ "async": "^2.5", "blessed": "^0.1.81", "chalk": "^1.1", - "chokidar": "^1.7", + "chokidar": "^2.0", "cli-table-redemption": "^1.0.0", - "commander": "2.12.2", + "commander": "2.13.0", "cron": "^1.3", "debug": "^3.0", "eventemitter2": "1.0.5", "fclone": "1.0.11", "mkdirp": "0.5.1", "moment": "^2.19", - "needle": "1.6.0", + "needle": "^2.1.0", "nssocket": "0.6.0", "pidusage": "^1.2.0", "pm2-axon": "3.1.0", @@ -189,7 +189,7 @@ "yamljs": "^0.3.0" }, "devDependencies": { - "mocha": "^3.5", + "mocha": "^5", "should": "^11" }, "optionalDependencies": { diff --git a/test/mocha.opts b/test/mocha.opts index 1e35b83e0..287882b39 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1 +1,2 @@ --timeout 25000 +--exit From f7710bbcf8d1e467ffe3b5a2ebb16a60161da61b Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Tue, 30 Jan 2018 16:38:23 +0100 Subject: [PATCH 12/36] downgrade chokidar --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 28cfed820..f75c37e02 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,7 @@ "async": "^2.5", "blessed": "^0.1.81", "chalk": "^1.1", - "chokidar": "^2.0", + "chokidar": "^1.7", "cli-table-redemption": "^1.0.0", "commander": "2.13.0", "cron": "^1.3", From be38055a5078ce31c67507003f19302169749f32 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Tue, 30 Jan 2018 16:49:07 +0100 Subject: [PATCH 13/36] downgrade mocha + reup chokidar --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f75c37e02..d2987894f 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,7 @@ "async": "^2.5", "blessed": "^0.1.81", "chalk": "^1.1", - "chokidar": "^1.7", + "chokidar": "^2", "cli-table-redemption": "^1.0.0", "commander": "2.13.0", "cron": "^1.3", @@ -189,7 +189,7 @@ "yamljs": "^0.3.0" }, "devDependencies": { - "mocha": "^5", + "mocha": "^4", "should": "^11" }, "optionalDependencies": { From 18053e3057add2e7e991729b0e32030522683902 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Tue, 30 Jan 2018 17:02:10 +0100 Subject: [PATCH 14/36] (chore) downgrade mocha --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d2987894f..44993e991 100644 --- a/package.json +++ b/package.json @@ -189,7 +189,7 @@ "yamljs": "^0.3.0" }, "devDependencies": { - "mocha": "^4", + "mocha": "^3.5", "should": "^11" }, "optionalDependencies": { From 517d5a9f63ced3d05041811f7309abf3a90a4d78 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 31 Jan 2018 10:17:51 +0100 Subject: [PATCH 15/36] feat: allow pm2 to install gc-stats --- lib/API/Modules/Modularizer.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index 00e7e3988..d08585445 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -50,6 +50,19 @@ Modularizer.install = function(CLI, module_name, opts, cb) { return false; } + if (module_name === 'gc-stats') { + installLangModule('gc-stats', function(err) { + if (err) { + Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green('gc-stats installation has FAILED (checkout previous logs)')); + return cb(err); + } + + Common.printOut(cst.PREFIX_MSG + chalk.bold.green('gc-stats ENABLED')); + return cb(); + }); + return false; + } + if (module_name.indexOf('typescript') > -1) { // Special dependency install return installLangModule(module_name, function(e) { From 8cad60b39f06069a99944fdc69011399fb05b536 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 31 Jan 2018 15:08:31 +0100 Subject: [PATCH 16/36] feat: allow pm2 to enable v8 data collecting from pmx --- bin/pm2 | 1 + lib/API/schema.json | 5 +++++ lib/ProcessContainer.js | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/pm2 b/bin/pm2 index aeb4aa481..d8f8db781 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -85,6 +85,7 @@ commander.version(pkg.version) .option('--disable-trace', 'disable transaction tracing with km') .option('--attach', 'attach logging after your start/restart/stop/reload') .option('--sort ', 'sort process according to field\'s name') + .option('--v8', 'enable v8 data collecting') .usage('[cmd] app'); commander.on('--help', function() { diff --git a/lib/API/schema.json b/lib/API/schema.json index 97400a3b7..1f23eb02f 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -192,6 +192,11 @@ "boolean" ] }, + "v8": { + "type": [ + "boolean" + ] + }, "increment_var": { "type": "string" }, diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index 2b1b3f176..573400cae 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -33,7 +33,8 @@ delete process.env.pm2_env; 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 + http: process.env.km_link == 'true' || false, + v8: process.env.v8 === 'true' || false }); var stdFile = pm2_env.pm_log_path; From 6d73933382a4713e979bfd63e20b4d0c7d813f0b Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Fri, 2 Feb 2018 01:21:49 +0100 Subject: [PATCH 17/36] feat: upgrade pmx to git development branch --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 44993e991..54b53b484 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", - "pmx": "~1.5.*", + "pmx": "keymetrics/pmx#development", "promptly": "2.2.0", "semver": "^5.3", "shelljs": "0.7.8", From 34b9607c2fb329e8d7c8e548ebb34a7932ca5412 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Fri, 2 Feb 2018 01:27:44 +0100 Subject: [PATCH 18/36] fix: impact v8 flag in fork mode also --- lib/ProcessContainerFork.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index c612adb6d..989308b08 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -7,7 +7,8 @@ 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 + http: process.env.km_link == 'true' || false, + v8: process.env.v8 === 'true' || false }); } @@ -61,7 +62,7 @@ if (process.env.uid || process.env.gid) { process.setgid(process.env.gid); if (process.env.uid){ // 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); process.setgid(new_gid); process.setuid(process.env.uid); From 6b247725b6885bd40cc6090efcfa97ecae4d0fde Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Fri, 2 Feb 2018 11:25:42 +0100 Subject: [PATCH 19/36] feat: ignore signal when running in --no-daemon --- lib/Client.js | 3 ++- lib/Daemon.js | 13 ++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/Client.js b/lib/Client.js index 1a5dce15d..ab4c6fb7f 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -69,7 +69,8 @@ Client.prototype.start = function(cb) { var daemon = new Daemon({ pub_socket_file : that.conf.DAEMON_PUB_PORT, 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 }); console.log('Launching in no daemon mode'); diff --git a/lib/Daemon.js b/lib/Daemon.js index 019197522..26c9c98ef 100644 --- a/lib/Daemon.js +++ b/lib/Daemon.js @@ -20,6 +20,7 @@ var fmt = require('./tools/fmt.js'); var Daemon = module.exports = function(opts) { if (!opts) opts = {}; + this.ignore_signals = opts.ignore_signals || false; this.rpc_socket_ready = false; this.pub_socket_ready = false; @@ -89,7 +90,8 @@ Daemon.prototype.innerStart = function(cb) { console.error(e.stack || e); } - this.handleSignals(); + if (this.ignore_signals != true) + this.handleSignals(); /** * Pub system for real time notifications @@ -255,18 +257,11 @@ Daemon.prototype.close = function(opts, cb) { msg : 'pm2 has been killed via CLI' }); - fmt.sep(); - fmt.title('Stopping PM2'); - fmt.field('Time', new Date()); - fmt.sep(); - /** * Cleanly kill pm2 */ that.rpc_socket.close(function() { - console.log('RPC closed'); that.pub_socket.close(function() { - console.log('PUB closed'); // notify cli that the daemon is shuting down (only under unix since windows doesnt handle signals) if (cst.IS_WINDOWS === false) { @@ -335,7 +330,7 @@ Daemon.prototype.gracefullExit = function() { try { fs.unlinkSync(that.pid_path); } catch(e) {} - console.log('[PM2] Exited peacefully'); + console.log('Exited peacefully'); process.exit(0); }); }); From 7c44f532cd32455c67ce5877ce55233a3a35b6dd Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Fri, 2 Feb 2018 11:27:33 +0100 Subject: [PATCH 20/36] refactor: no more interactive spinner for connection to KM + change pm2 log format + remove some logs --- lib/God.js | 2 +- lib/Interactor/InteractorDaemonizer.js | 6 +----- lib/Utility.js | 4 ++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/God.js b/lib/God.js index 8df9b7f5a..a7dd8c3d5 100644 --- a/lib/God.js +++ b/lib/God.js @@ -359,7 +359,7 @@ God.handleExit = function handleExit(clu, exit_code, kill_signal) { God.notify('exit', proc); 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; } diff --git a/lib/Interactor/InteractorDaemonizer.js b/lib/Interactor/InteractorDaemonizer.js index c50905ddd..2d87715ff 100644 --- a/lib/Interactor/InteractorDaemonizer.js +++ b/lib/Interactor/InteractorDaemonizer.js @@ -232,7 +232,7 @@ var daemonize = function(conf, infos, cb) { stdio : ['ipc', out, err] }); - UX.processing.start(); + console.log('[KM] Connecting'); fs.writeFileSync(conf.INTERACTOR_PID_PATH, child.pid); @@ -246,8 +246,6 @@ var daemonize = function(conf, infos, cb) { child.unref(); 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); child.removeAllListeners('message'); child.removeAllListeners('error'); @@ -259,8 +257,6 @@ var daemonize = function(conf, infos, cb) { clearTimeout(t); debug('Interactor daemon launched', msg); - UX.processing.stop(); - if (msg.debug) { return cb(null, msg, child); } diff --git a/lib/Utility.js b/lib/Utility.js index 169d86fd8..a6f1f318e 100644 --- a/lib/Utility.js +++ b/lib/Utility.js @@ -84,7 +84,7 @@ var Utility = module.exports = { // Generate timestamp prefix function timestamp(){ - return moment().format(cst.PM2_LOG_DATE_FORMAT) + ': '; + return '[' + moment().format(cst.PM2_LOG_DATE_FORMAT) + ']'; } var hacks = ['info', 'log', 'error', 'warn'], consoled = {}; @@ -108,7 +108,7 @@ var Utility = module.exports = { }); } // 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); }; }); From 3036c4c461296db86ca21a6d9b9400c5353ef054 Mon Sep 17 00:00:00 2001 From: Alexandre Strzelewicz Date: Fri, 2 Feb 2018 12:14:53 +0100 Subject: [PATCH 21/36] fix: auto-exit edge case fix + pm2 no daemon mode + log in raw by default + less logs --- lib/binaries/Runtime4Docker.js | 43 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/binaries/Runtime4Docker.js b/lib/binaries/Runtime4Docker.js index 8d05fc682..53ee13456 100644 --- a/lib/binaries/Runtime4Docker.js +++ b/lib/binaries/Runtime4Docker.js @@ -40,21 +40,17 @@ function start(cmd, opts) { 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 + daemon_mode : false }); - if (commander.autoExit) { - autoExit(); + if (opts.web) { + var port = opts.web === true ? cst.WEB_PORT : opts.web; + pm2.web(port); } - pm2.connect(function() { - - if (opts.web) { - var port = opts.web === true ? cst.WEB_PORT : opts.web; - pm2.web(port); - } - - run(cmd, opts); + run(cmd, opts, function() { + if (commander.autoExit) + autoExit(); }); } @@ -95,25 +91,29 @@ process.on('SIGTERM', function() { exitPM2(); }); -function run(cmd, opts) { +function run(cmd, opts, cb) { var needRaw = commander.raw; var timestamp = commander.timestamp; + if (commander.json === true) + Log.jsonStream(pm2.Client, 'all'); + else if (commander.format === true) + Log.formatStream(pm2.Client, 'all', false, 'YYYY-MM-DD-HH:mm:ssZZ'); + else + Log.stream(pm2.Client, 'all', needRaw, timestamp, true); + function exec() { pm2.start(cmd, opts, function(err, obj) { if (err) { console.error(err.message || err); return exitPM2(); } - - var pm_id = obj[0].pm2_env.pm_id; - - 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 (obj && obj.length == 0) { + console.error('Failed to start application %s', cmd); + return exitPM2(); + } + // ack start + cb(); if (process.env.PM2_RUNTIME_DEBUG) pm2.disconnect(function() {}); @@ -124,7 +124,6 @@ function run(cmd, opts) { } function exitPM2() { - console.log('Exiting PM2'); pm2.kill(function() { process.exit(0); }); From 51ff04be948af77a6442588468a633434c3042ac Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Feb 2018 14:56:23 +0100 Subject: [PATCH 22/36] feat: allow pm2 to install and enable event-loop-inspector data collecting --- bin/pm2 | 1 + lib/API/Modules/Modularizer.js | 13 +++++++++++++ lib/API/schema.json | 5 +++++ lib/ProcessContainer.js | 11 ++++++----- lib/ProcessContainerFork.js | 9 +++++---- 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index d8f8db781..45a4734a1 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -86,6 +86,7 @@ commander.version(pkg.version) .option('--attach', 'attach logging after your start/restart/stop/reload') .option('--sort ', 'sort process according to field\'s name') .option('--v8', 'enable v8 data collecting') + .option('--event-loop-inspector', 'enable event-loop-inspector dump in pmx') .usage('[cmd] app'); commander.on('--help', function() { diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index d08585445..6d318e7fe 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -63,6 +63,19 @@ Modularizer.install = function(CLI, module_name, opts, cb) { return false; } + if (module_name === 'event-loop-inspector') { + installLangModule('event-loop-inspector', function(err) { + if (err) { + Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green('event-loop-inspector installation has FAILED (checkout previous logs)')); + return cb(err); + } + + Common.printOut(cst.PREFIX_MSG + chalk.bold.green('event-loop-inspector ENABLED')); + return cb(); + }); + return false; + } + if (module_name.indexOf('typescript') > -1) { // Special dependency install return installLangModule(module_name, function(e) { diff --git a/lib/API/schema.json b/lib/API/schema.json index 1f23eb02f..97495a153 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -197,6 +197,11 @@ "boolean" ] }, + "event-loop-inspector": { + "type": [ + "boolean" + ] + }, "increment_var": { "type": "string" }, diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index 573400cae..16b4a55c3 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -30,17 +30,18 @@ delete process.env.pm2_env; (function ProcessContainer() { var fs = require('fs'); - 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, - v8: process.env.v8 === 'true' || false + transactions: (process.env.km_link === 'true' && process.env.trace === 'true') || false, + http: process.env.km_link === 'true' || false, + v8: process.env.v8 === 'true' || false, + event_loop_dump: process.env['event-loop-inspector'] === 'true' || false }); + } var stdFile = pm2_env.pm_log_path; var outFile = pm2_env.pm_out_log_path; var errFile = pm2_env.pm_err_log_path; - var pmId = pm2_env.pm_id; var pidFile = pm2_env.pm_pid_path; var script = pm2_env.pm_exec_path; var cronRestart = pm2_env.cron_restart; diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index 989308b08..fb0291adb 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -4,11 +4,12 @@ * can be found in the LICENSE file. */ // 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, - v8: process.env.v8 === 'true' || false + transactions: (process.env.km_link === 'true' && process.env.trace === 'true') || false, + http: process.env.km_link === 'true' || false, + v8: process.env.v8 === 'true' || false, + event_loop_dump: process.env['event-loop-inspector'] === 'true' || false }); } From 99a37c003daf2ca3cac29be78074bc2f817e49fb Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 2 Feb 2018 15:32:11 +0100 Subject: [PATCH 23/36] chore: remove unused files --- test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json | 1 - test/fixtures/pm2-dev/$HOME/.pm3/touch | 1 - test/fixtures/pm2-dev/exited_app.js | 2 ++ 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json delete mode 100644 test/fixtures/pm2-dev/$HOME/.pm3/touch create mode 100644 test/fixtures/pm2-dev/exited_app.js diff --git a/test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json b/test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json deleted file mode 100644 index 9e26dfeeb..000000000 --- a/test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/test/fixtures/pm2-dev/$HOME/.pm3/touch b/test/fixtures/pm2-dev/$HOME/.pm3/touch deleted file mode 100644 index ad2dd20b0..000000000 --- a/test/fixtures/pm2-dev/$HOME/.pm3/touch +++ /dev/null @@ -1 +0,0 @@ -1498811729303 \ No newline at end of file diff --git a/test/fixtures/pm2-dev/exited_app.js b/test/fixtures/pm2-dev/exited_app.js new file mode 100644 index 000000000..df1fc8096 --- /dev/null +++ b/test/fixtures/pm2-dev/exited_app.js @@ -0,0 +1,2 @@ + +throw new Error('exit') From 893cb33f2e88d835bb6c8f2139cefe30e946e264 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 2 Feb 2018 15:32:54 +0100 Subject: [PATCH 24/36] feat: pm2 pid command --- bin/pm2 | 6 ++++++ lib/API/Extra.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/bin/pm2 b/bin/pm2 index d8f8db781..81dca3a95 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -310,6 +310,12 @@ commander.command('startOrReload ') pm2._startJson(file, commander, 'reloadProcessId'); }); +commander.command('pid [app_name]') + .description('return pid of [app_name] or all') + .action(function(app) { + pm2.getPID(app); + }); + commander.command('startOrGracefulReload ') .description('start or gracefully reload JSON file') .action(function(file) { diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 0c017ab6e..00f445dde 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -117,6 +117,34 @@ module.exports = function(CLI) { }); }; + 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); + }) + } /** * Create PM2 memory snapshot * @method getVersion From aadfef26d3b6a3efcab652e2b96a53b0dfc45844 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 2 Feb 2018 15:39:17 +0100 Subject: [PATCH 25/36] refactor: deep pm2-runtime refactor #3408 #3257 #3266 --- lib/API/Log.js | 16 ++- lib/Client.js | 2 +- lib/God.js | 2 +- lib/binaries/Runtime4Docker.js | 240 +++++++++++++++++---------------- test/bash/cli-actions-2.sh | 7 + test/bash/pm2-runtime.sh | 43 ++++-- 6 files changed, 180 insertions(+), 130 deletions(-) diff --git a/lib/API/Log.js b/lib/API/Log.js index 1e1c552c0..37ad02974 100644 --- a/lib/API/Log.js +++ b/lib/API/Log.js @@ -194,34 +194,42 @@ Log.devStream = function(Client, id, raw, timestamp, exclusive) { }); }; -Log.jsonStream = function(Client, app_name) { +Log.jsonStream = function(Client, id) { var that = this; Client.launchBus(function(err, bus) { if (err) console.error(err); bus.on('process:event', function(packet) { - console.log(JSON.stringify({ + process.stdout.write(JSON.stringify({ timestamp : moment(packet.at), type : 'process_event', status : packet.event, app_name : packet.process.name })); + 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, timestamp : moment(packet.at), type : type, process_id : packet.process.pm_id, app_name : packet.process.name })); + process.stdout.write('\n'); }); }); }; diff --git a/lib/Client.js b/lib/Client.js index ab4c6fb7f..74103fd3b 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -87,7 +87,7 @@ Client.prototype.start = function(cb) { that.launchRPC(function(err, meta) { return cb(null, { daemon_mode : that.conf.daemon_mode, - new_pm2_instance : false, + new_pm2_instance : true, rpc_socket_file : that.rpc_socket_file, pub_socket_file : that.pub_socket_file, pm2_home : that.pm2_home diff --git a/lib/God.js b/lib/God.js index a7dd8c3d5..dc0019972 100644 --- a/lib/God.js +++ b/lib/God.js @@ -452,7 +452,7 @@ God.finalizeProcedure = function finalizeProcedure(proc) { !proc.pm2_env || proc.pm2_env.status == cst.STOPPED_STATUS || 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'); } proc.pm2_env.vizion_running = false; diff --git a/lib/binaries/Runtime4Docker.js b/lib/binaries/Runtime4Docker.js index 53ee13456..0094f063d 100644 --- a/lib/binaries/Runtime4Docker.js +++ b/lib/binaries/Runtime4Docker.js @@ -1,7 +1,7 @@ 'use strict'; /** - * Specialized PM2 CLI for Docker + * Specialized PM2 CLI for Containers */ var commander = require('commander'); var debug = require('debug')('pm2:cli'); @@ -10,20 +10,26 @@ var Log = require('../../lib/API/Log'); var cst = require('../../constants.js'); var pkg = require('../../package.json'); 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 ', '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 ', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"') + .option('-n --name ', 'set a for script') + .option('--max-memory-restart ', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)') + .option('-c --cron ', 'restart a running process based on a cron pattern') + .option('--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('--json', 'output logs in json format') + .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('--delay ', 'delay start of configuration file by ', 0) .option('--web [port]', 'launch process web api on [port] (default to 9615)') .option('--only ', 'only act on one application of configuration') @@ -32,38 +38,18 @@ commander.version(pkg.version) .option('--watch', 'watch and restart application on file change') .option('--error ', 'error log file destination (default disabled)', '/dev/null') .option('--output ', 'output log file destination (default disabled)', '/dev/null') + .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 : false - }); - - if (opts.web) { - var port = opts.web === true ? cst.WEB_PORT : opts.web; - pm2.web(port); - } - - run(cmd, opts, function() { - if (commander.autoExit) - autoExit(); - }); -} - commander.command('*') .action(function(cmd){ - start(cmd, commander); + Runtime.instanciate(cmd); }); -// @todo need to allow passing same option than pm2 start commander.command('start ') .description('start an application or json ecosystem file') .action(function(cmd) { - start(cmd, commander); + Runtime.instanciate(cmd); }); if (process.argv.length == 2) { @@ -71,105 +57,127 @@ if (process.argv.length == 2) { process.exit(1); } -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." - ); - - process.argv.splice(autoExitIndex, 1); -} - -commander.parse(process.argv); +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.on('SIGINT', function() { - exitPM2(); -}); - -process.on('SIGTERM', function() { - exitPM2(); -}); - -function run(cmd, opts, cb) { - var needRaw = commander.raw; - var timestamp = commander.timestamp; - - if (commander.json === true) - Log.jsonStream(pm2.Client, 'all'); - else if (commander.format === true) - Log.formatStream(pm2.Client, 'all', false, 'YYYY-MM-DD-HH:mm:ssZZ'); - else - Log.stream(pm2.Client, 'all', needRaw, timestamp, true); - - function exec() { - pm2.start(cmd, opts, function(err, obj) { - if (err) { - console.error(err.message || err); - return exitPM2(); - } - if (obj && obj.length == 0) { - console.error('Failed to start application %s', cmd); - return exitPM2(); + this.pm2.connect(function(err, pm2_meta) { + if (pm2_meta.new_pm2_instance == false) { + console.warn('[WARN] PM2 Daemon is already running') } - // ack start - cb(); - if (process.env.PM2_RUNTIME_DEBUG) - pm2.disconnect(function() {}); + process.on('SIGINT', function() { + Runtime.exit(); + }); - }); - } - setTimeout(exec.bind(this), opts.delay * 1000); -} + process.on('SIGTERM', function() { + Runtime.exit(); + }); -function exitPM2() { - pm2.kill(function() { - process.exit(0); - }); -} + Runtime.startLogStreaming(); + Runtime.startApp(cmd, function(err) { + if (err) { + console.error(err.message || err); + return Runtime.exit(); + } + }); + }); + }, + + /** + * 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); + }, + + /** + * 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')) + + if (commander.web) { + var port = commander.web === true ? cst.WEB_PORT : commander.web; + Runtime.pm2.web(port); + } -/** - * Exit current PM2 instance if 0 app is online - * function activated via --auto-exit - */ -function autoExit() { - var interval = 3000; - var aliveInterval = interval * 1.5; - - setTimeout(function () { - var alive = false - var aliveTimer = setTimeout(function () { - if (!alive) { - console.error('PM2 Daemon is dead'); - process.exit(1); - } - }, aliveInterval); + if (commander.autoExit) + Runtime.autoExitWorker(); - pm2.list(function (err, apps) { - if (err) { - console.log('pm2.list got error') - console.error(err); - exitPM2(); - } + // For Testing purpose (allow to auto exit CLI) + if (process.env.PM2_RUNTIME_DEBUG) + Runtime.pm2.disconnect(function() {}); - clearTimeout(aliveTimer); - alive = true; + return cb(null, obj); + }); + } + // via --delay option + setTimeout(exec.bind(this), commander.delay * 1000); + }, + + /** + * Exit runtime mgmt + */ + exit : function() { + if (!this.pm2) return process.exit(1); + + this.pm2.kill(function() { + process.exit(0); + }); + }, + + /** + * Exit current PM2 instance if 0 app is online + * function activated via --auto-exit + */ + autoExitWorker : function() { + var interval = 1000; + + var timer = setTimeout(function () { + Runtime.pm2.list(function (err, apps) { + if (err) { + console.error('Could not run pm2 list'); + return Runtime.autoExitWorker(); + } - var appOnline = 0; + var appOnline = 0; - apps.forEach(function (app) { - if (app.pm2_env.status === cst.ONLINE_STATUS || + apps.forEach(function (app) { + if (app.pm2_env.status === cst.ONLINE_STATUS || app.pm2_env.status === cst.LAUNCHING_STATUS) { - appOnline++; + 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); diff --git a/test/bash/cli-actions-2.sh b/test/bash/cli-actions-2.sh index 7cab8b283..02b50fc58 100644 --- a/test/bash/cli-actions-2.sh +++ b/test/bash/cli-actions-2.sh @@ -30,6 +30,13 @@ should 'should app be online once restart called' 'online' 1 $pm2 delete all +############## PID +$pm2 start 001-test.js --name "test" +should 'should app be online' 'online' 1 +$pm2 pid > /tmp/pid-tmp +$pm2 pid test +$pm2 delete all + ############### echo "Start application with filename starting with a numeric" diff --git a/test/bash/pm2-runtime.sh b/test/bash/pm2-runtime.sh index c58e55c84..f07131a35 100644 --- a/test/bash/pm2-runtime.sh +++ b/test/bash/pm2-runtime.sh @@ -3,27 +3,54 @@ SRC=$(cd $(dirname "$0"); pwd) source "${SRC}/include.sh" -export PM2_HOME="$HOME/.pm3" - -pm2runtime="`type -P node` `pwd`/bin/pm2-runtime" +pm2_runtime="`type -P node` `pwd`/bin/pm2-runtime" export PM2_RUNTIME_DEBUG='true' cd $file_path/pm2-dev -$pm2 delete all +# +# Simple start with 4 apps +# +$pm2 kill -# Test with js -$pm2runtime app.js -i 4 +$pm2_runtime app.js -i 4 should 'should have started 4 apps' 'online' 4 -$pm2 delete all +$pm2 kill +# # Test with json and args -$pm2runtime app.json +# +$pm2_runtime app.json should 'should have started 1 apps' 'online' 1 $pm2 prettylist | grep "watch: \[ 'server', 'client' \]" spec "Should application have two watch arguments" $pm2 prettylist | grep "ignore_watch: \[ 'node_modules', 'client/img' \]" spec "Should application have two ignore_watch arguments" $pm2 kill + +# Restore default behavior for exit checks +unset PM2_RUNTIME_DEBUG + +# +# --no-autorestart checks +# +# $pm2_runtime app.js --no-autorestart +# PID_PM2=$! +# $pm2 pid app +# echo "OK" +# PID=`cat /tmp/pid` +# echo $PID +# kill $PID +# sleep 3 +# pgrep "PM2" +# ispec "PM2 runtime should be killed because no app is running" + +# +# Auto Exit Worker +# +$pm2_runtime exited_app.js 2> /dev/null +sleep 1 +pgrep "PM2" +ispec "PM2 runtime should be killed because no app is running" From 2b29c110b4d88a135ee97074d050354a70b61c5a Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 2 Feb 2018 15:50:26 +0100 Subject: [PATCH 26/36] fix: make sure not pm2 is running --- test/bash/pm2-runtime.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/bash/pm2-runtime.sh b/test/bash/pm2-runtime.sh index f07131a35..da29b919f 100644 --- a/test/bash/pm2-runtime.sh +++ b/test/bash/pm2-runtime.sh @@ -13,6 +13,7 @@ cd $file_path/pm2-dev # Simple start with 4 apps # $pm2 kill +pkill -f PM2 $pm2_runtime app.js -i 4 should 'should have started 4 apps' 'online' 4 From 87fe276bf8080e6f51c9b39fe28d21e315298568 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 2 Feb 2018 17:06:21 +0100 Subject: [PATCH 27/36] chore: remove --exit from mocha.opts --- test/mocha.opts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/mocha.opts b/test/mocha.opts index 287882b39..1e35b83e0 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,2 +1 @@ --timeout 25000 ---exit From 0fc3cda6c4a275f60c68ea7e8126df3a60e26424 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 2 Feb 2018 18:07:50 +0100 Subject: [PATCH 28/36] fix: replace dash with underscore --- lib/API/schema.json | 2 +- lib/ProcessContainer.js | 2 +- lib/ProcessContainerFork.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/API/schema.json b/lib/API/schema.json index 97495a153..97274d7af 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -197,7 +197,7 @@ "boolean" ] }, - "event-loop-inspector": { + "event_loop_inspector": { "type": [ "boolean" ] diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index 16b4a55c3..81c1fb508 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -35,7 +35,7 @@ delete process.env.pm2_env; transactions: (process.env.km_link === 'true' && process.env.trace === 'true') || false, http: process.env.km_link === 'true' || false, v8: process.env.v8 === 'true' || false, - event_loop_dump: process.env['event-loop-inspector'] === 'true' || false + event_loop_dump: process.env['event_loop_inspector'] === 'true' || false }); } diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index fb0291adb..fd992498f 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -9,7 +9,7 @@ if (process.env.pmx !== 'false') { transactions: (process.env.km_link === 'true' && process.env.trace === 'true') || false, http: process.env.km_link === 'true' || false, v8: process.env.v8 === 'true' || false, - event_loop_dump: process.env['event-loop-inspector'] === 'true' || false + event_loop_dump: process.env['event_loop_inspector'] === 'true' || false }); } From b52a30eb5f3ea0d062f4e906804049151473ae30 Mon Sep 17 00:00:00 2001 From: Unitech Date: Fri, 2 Feb 2018 18:59:06 +0100 Subject: [PATCH 29/36] chore: switch to published pmx(@next) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 54b53b484..ac104f0a4 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", - "pmx": "keymetrics/pmx#development", + "pmx": "1.6.1-next", "promptly": "2.2.0", "semver": "^5.3", "shelljs": "0.7.8", From 5b8fece589f4726b1aa700da1e13159e75781599 Mon Sep 17 00:00:00 2001 From: Unitech Date: Sat, 3 Feb 2018 11:56:04 +0100 Subject: [PATCH 30/36] chore: upgrade pmx dep --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac104f0a4..ee83eaa46 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", - "pmx": "1.6.1-next", + "pmx": "1.6.2-next", "promptly": "2.2.0", "semver": "^5.3", "shelljs": "0.7.8", From 4e9503e3487bbd3fa758e596a77bf8d7a87639c7 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Feb 2018 13:52:48 +0100 Subject: [PATCH 31/36] feat: allow pm2 to install a set of module as one single command and add deep-monitoring. --- lib/API/Modules/Modularizer.js | 130 ++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 51 deletions(-) diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index 6d318e7fe..abb736af1 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -21,6 +21,14 @@ var mkdirp = require('mkdirp'); var MODULE_CONF_PREFIX = 'module-db-v2'; +var KNOWN_MODULES = { + 'deep-monitoring': { + 'dependencies': ['v8-profiler-node8', 'gc-stats', 'event-loop-inspector'] + }, + 'gc-stats': {name: 'gc-stats'}, + 'event-loop-inspector': {name: 'event-loop-inspector'} +}; + /** * PM2 Module System. * Features: @@ -32,100 +40,100 @@ var MODULE_CONF_PREFIX = 'module-db-v2'; * - Auto discover script to launch (first it checks the apps field, then bin and finally main attr) * - Generate sample module via pm2 module:generate */ -Modularizer.install = function(CLI, module_name, opts, cb) { - Common.printOut(cst.PREFIX_MSG_MOD + 'Installing module ' + module_name); - - var canonic_module_name = Utility.getCanonicModuleName(module_name); - - 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); +Modularizer.install = function (CLI, moduleName, opts, cb) { + Common.printOut(cst.PREFIX_MSG_MOD + 'Installing module ' + moduleName); + + var canonicModuleName = Utility.getCanonicModuleName(moduleName); + + if (KNOWN_MODULES.hasOwnProperty(moduleName)) { + var currentModule = KNOWN_MODULES[moduleName]; + + if (currentModule && currentModule.hasOwnProperty('dependencies')) { + var functionList = []; + for (var i = 0; i < currentModule.dependencies.length; i++) { + functionList.push((function (index) { + return function (callback) { + installModuleByName(currentModule.dependencies[index], function (err) { + callback(null, {module: currentModule.dependencies[index], err: err}); + }, false); + }; + })(i)); } - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('V8 profiling ENABLED')); - return cb(); - }); - return false; - } + async.parallel(functionList, function (err, results) { + for (var i = 0; i < results.length; i++) { + if (results[i].err) { + err = results[i].err; + Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(results[i].module + ' installation has FAILED (checkout previous logs)')); + } else { + Common.printOut(cst.PREFIX_MSG + chalk.bold.green(results[i].module + ' ENABLED')); + } + } - if (module_name === 'gc-stats') { - installLangModule('gc-stats', function(err) { - if (err) { - Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green('gc-stats installation has FAILED (checkout previous logs)')); - return cb(err); - } + cb(err); + }); + } else { + installModuleByName(currentModule.name, cb); + } - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('gc-stats ENABLED')); - return cb(); - }); return false; } - if (module_name === 'event-loop-inspector') { - installLangModule('event-loop-inspector', function(err) { - if (err) { - Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green('event-loop-inspector installation has FAILED (checkout previous logs)')); - return cb(err); - } - - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('event-loop-inspector ENABLED')); - return cb(); - }); + if (moduleName === 'v8-profiler' || moduleName === 'profiler') { + installModuleByName('v8-profiler-node8', cb); return false; } - if (module_name.indexOf('typescript') > -1) { + if (moduleName.indexOf('typescript') > -1) { // Special dependency install - return installLangModule(module_name, function(e) { - installLangModule('ts-node@latest', function(e) { + return installLangModule(moduleName, function (e) { + installLangModule('ts-node@latest', function (e) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Typescript support enabled')); return cb(e); }); }); } - if (module_name == 'livescript') { - return installLangModule('livescript', function(e) { + if (moduleName === 'livescript') { + return installLangModule('livescript', function (e) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Livescript support enabled')); return cb(e); }); } - if (module_name.indexOf('coffee-script') > -1) { - return installLangModule(module_name, function(e) { + if (moduleName.indexOf('coffee-script') > -1) { + return installLangModule(moduleName, function (e) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Coffeescript v1 support enabled')); return cb(e); }); } - if (module_name.indexOf('coffeescript') > -1) { - return installLangModule(module_name, function(e) { + if (moduleName.indexOf('coffeescript') > -1) { + return installLangModule(moduleName, function (e) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Coffeescript v2 support enabled')); return cb(e); }); } - moduleExist(CLI, canonic_module_name, function(exists) { + moduleExist(CLI, canonicModuleName, function (exists) { if (exists) { // Update Common.printOut(cst.PREFIX_MSG_MOD + 'Module already installed. Updating.'); // 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); }); } // Install - Modularizer.installModule(CLI, module_name, opts, cb); - }) + Modularizer.installModule(CLI, moduleName, opts, cb); + }); }; Modularizer.installModule = function(CLI, module_name, opts, cb) { @@ -569,6 +577,26 @@ Modularizer.generateSample = function(app_name, cb) { }); }; +function installModuleByName (moduleName, cb, verbose) { + if (!moduleName || moduleName.length === 0) { + return cb(new Error('No module name !')); + } + + if (typeof verbose === 'undefined') { + verbose = true; + } + + installLangModule(moduleName, function (err) { + if (err) { + if (verbose) { Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(moduleName + ' installation has FAILED (checkout previous logs)')); } + return cb(err); + } + + if (verbose) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green(moduleName + ' ENABLED')); } + return cb(); + }); +} + function installLangModule(module_name, cb) { var node_module_path = path.resolve(path.join(__dirname, '../../../')); Common.printOut(cst.PREFIX_MSG_MOD + 'Calling ' + chalk.bold.red('[NPM]') + ' to install ' + module_name + ' ...'); From 0ccd25b04e5e342170c6ec8bcdb38e8ab3bf4982 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 5 Feb 2018 15:10:21 +0100 Subject: [PATCH 32/36] feat: add flag to enable deep-monitoring --- bin/pm2 | 1 + lib/API/schema.json | 5 +++++ lib/ProcessContainer.js | 6 +++--- lib/ProcessContainerFork.js | 6 +++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/bin/pm2 b/bin/pm2 index feca91ee9..124a47aac 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -87,6 +87,7 @@ commander.version(pkg.version) .option('--sort ', 'sort process according to field\'s name') .option('--v8', 'enable v8 data collecting') .option('--event-loop-inspector', 'enable event-loop-inspector dump in pmx') + .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace') .usage('[cmd] app'); commander.on('--help', function() { diff --git a/lib/API/schema.json b/lib/API/schema.json index 97274d7af..a74b138e3 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -202,6 +202,11 @@ "boolean" ] }, + "deep_monitoring": { + "type": [ + "boolean" + ] + }, "increment_var": { "type": "string" }, diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index 81c1fb508..4360d6de6 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -32,10 +32,10 @@ delete process.env.pm2_env; if (process.env.pmx !== 'false') { require('pmx').init({ - transactions: (process.env.km_link === 'true' && process.env.trace === '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' || false, - event_loop_dump: process.env['event_loop_inspector'] === '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 }); } diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index fd992498f..a9b822857 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -6,10 +6,10 @@ // Inject custom modules if (process.env.pmx !== 'false') { require('pmx').init({ - transactions: (process.env.km_link === 'true' && process.env.trace === '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' || false, - event_loop_dump: process.env['event_loop_inspector'] === '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 }); } From a70a2df46f111f3d477c731e210fb700c0d1916b Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Mon, 5 Feb 2018 17:40:27 +0100 Subject: [PATCH 33/36] feat: add deep_metrics to deep_monitoring flag --- lib/ProcessContainer.js | 3 ++- lib/ProcessContainerFork.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index 4360d6de6..db9540dd6 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -35,7 +35,8 @@ delete process.env.pm2_env; 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 + event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, + deep_metrics: process.env.deep_monitoring === 'true' || false }); } diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index a9b822857..6d1b0cebb 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -9,7 +9,8 @@ if (process.env.pmx !== '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 + event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, + deep_metrics: process.env.deep_monitoring === 'true' || false }); } From 4f7767a2213de10fbbaaebcdce9f19632d532cbb Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 6 Feb 2018 08:26:22 +0100 Subject: [PATCH 34/36] chore: upgrade pmx to 1.6.3-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee83eaa46..fcdd8a987 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", - "pmx": "1.6.2-next", + "pmx": "1.6.3-next", "promptly": "2.2.0", "semver": "^5.3", "shelljs": "0.7.8", From 9de588b4c813fa0f63638ae5c8c0d051769a01e3 Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 6 Feb 2018 12:55:57 +0100 Subject: [PATCH 35/36] feat: --deep-monitoring available from pm2-runtime --- bin/pm2 | 2 +- lib/binaries/Runtime4Docker.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/pm2 b/bin/pm2 index 124a47aac..e43b1cc64 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -87,7 +87,7 @@ commander.version(pkg.version) .option('--sort ', 'sort process according to field\'s name') .option('--v8', 'enable v8 data collecting') .option('--event-loop-inspector', 'enable event-loop-inspector dump in pmx') - .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace') + .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)') .usage('[cmd] app'); commander.on('--help', function() { diff --git a/lib/binaries/Runtime4Docker.js b/lib/binaries/Runtime4Docker.js index 0094f063d..101089a93 100644 --- a/lib/binaries/Runtime4Docker.js +++ b/lib/binaries/Runtime4Docker.js @@ -38,6 +38,7 @@ commander.version(pkg.version) .option('--watch', 'watch and restart application on file change') .option('--error ', 'error log file destination (default disabled)', '/dev/null') .option('--output ', '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'); From a2e9a5be20f2219edf40b5af44f3b48cdb841973 Mon Sep 17 00:00:00 2001 From: Unitech Date: Tue, 6 Feb 2018 12:57:07 +0100 Subject: [PATCH 36/36] chore: 2.10.0-beta --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fcdd8a987..f8ba2bf04 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pm2", "preferGlobal": true, - "version": "2.9.3", + "version": "2.10.0-beta", "engines": { "node": ">=0.12" },