Skip to content

Commit

Permalink
refactor: deep pm2-runtime refactor #3408 #3257 #3266
Browse files Browse the repository at this point in the history
  • Loading branch information
Unitech committed Feb 2, 2018
1 parent 6687d49 commit c13b236
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 130 deletions.
16 changes: 12 additions & 4 deletions lib/API/Log.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
});
};
Expand Down
2 changes: 1 addition & 1 deletion lib/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/God.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
240 changes: 124 additions & 116 deletions lib/binaries/Runtime4Docker.js
Original file line number Diff line number Diff line change
@@ -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');
Expand All @@ -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 <number>', 'launch [number] of processes automatically load-balanced. Increase overall performances and performance stability.')
.option('--secret [key]', '[MONITORING] keymetrics secret key')
.option('--no-autorestart', 'start an app without automatic restart')
.option('--node-args <node_args>', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"')
.option('-n --name <name>', 'set a <name> for script')
.option('--max-memory-restart <memory>', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)')
.option('-c --cron <cron_pattern>', 'restart a running process based on a cron pattern')
.option('--interpreter <interpreter>', 'the interpreter pm2 should use for executing app (bash, python...)')
.option('--public [key]', '[MONITORING] keymetrics public key')
.option('--machine-name [name]', '[MONITORING] keymetrics machine name')
.option('--raw', 'raw log output')
.option('--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 <seconds>', 'delay start of configuration file by <seconds>', 0)
.option('--web [port]', 'launch process web api on [port] (default to 9615)')
.option('--only <application-name>', 'only act on one application of configuration')
Expand All @@ -32,144 +38,146 @@ commander.version(pkg.version)
.option('--watch', 'watch and restart application on file change')
.option('--error <path>', 'error log file destination (default disabled)', '/dev/null')
.option('--output <path>', '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 <app.js|json_file>')
.description('start an application or json ecosystem file')
.action(function(cmd) {
start(cmd, commander);
Runtime.instanciate(cmd);
});

if (process.argv.length == 2) {
commander.outputHelp();
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 <seconds> 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);
7 changes: 7 additions & 0 deletions test/bash/cli-actions-2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading

0 comments on commit c13b236

Please sign in to comment.