mirror of
https://github.com/Unitech/pm2.git
synced 2025-12-08 20:35:53 +00:00
0.9.9
This commit is contained in:
parent
c82a981f2e
commit
133cf24dee
4
.gitignore
vendored
4
.gitignore
vendored
@ -1 +1,3 @@
|
||||
node_modules/*
|
||||
node_modules/*
|
||||
pids/*
|
||||
logs/*
|
||||
|
||||
5
apps/auto-kill-echo.json
Normal file
5
apps/auto-kill-echo.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name" : "auto-kill",
|
||||
"script" : "./examples/echokill.js",
|
||||
"max" : "10"
|
||||
}
|
||||
8
apps/cluster-pm2.json
Normal file
8
apps/cluster-pm2.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"script" : "./examples/child.js",
|
||||
"fileError" : "logs/errLog.log",
|
||||
"fileOutput" : "logs/outLog.log",
|
||||
"pidFile" : "pids/child",
|
||||
"max" : "10",
|
||||
"instances" : "max"
|
||||
}
|
||||
5
apps/default-path-echo.json
Normal file
5
apps/default-path-echo.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name" : "echo-default",
|
||||
"script" : "examples/echo.js",
|
||||
"max" : "1"
|
||||
}
|
||||
7
apps/echo-pm2.json
Normal file
7
apps/echo-pm2.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"script" : "examples/echo.js",
|
||||
"fileError" : "logs/errEcho.log",
|
||||
"fileOutput" : "logs/outEcho.log",
|
||||
"pidFile" : "pids/echo",
|
||||
"max" : "1"
|
||||
}
|
||||
20
apps/multi-pm2.json
Normal file
20
apps/multi-pm2.json
Normal file
@ -0,0 +1,20 @@
|
||||
[{
|
||||
"script" : "examples/echo.js",
|
||||
"fileError" : "logs/errEcho.log",
|
||||
"fileOutput" : "logs/outEcho.log",
|
||||
"pidFile" : "pids/echo",
|
||||
"max" : "1"
|
||||
},{
|
||||
"script" : "./examples/child.js",
|
||||
"fileError" : "logs/errLog.log",
|
||||
"fileOutput" : "logs/outLog.log",
|
||||
"pidFile" : "pids/child",
|
||||
"max" : "10",
|
||||
"instances" : "max"
|
||||
},{
|
||||
"script" : "./examples/echokill.js",
|
||||
"fileError" : "logs/rLog.log",
|
||||
"fileOutput" : "logs/tLog.log",
|
||||
"pidFile" : "pids/kiii",
|
||||
"max" : "10"
|
||||
}]
|
||||
4
apps/no-name-echo.json
Normal file
4
apps/no-name-echo.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"script" : "examples/echo.js",
|
||||
"max" : "1"
|
||||
}
|
||||
355
bin/god
355
bin/god
@ -2,12 +2,253 @@
|
||||
|
||||
var Satan = require('../satan.js');
|
||||
var commander = require('commander');
|
||||
var Table = require('cli-table');
|
||||
var Monit = require('../lib/monit');
|
||||
var UX = require('../lib/cli-ux.js');
|
||||
var Log = require('../lib/Log.js');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
const VERSION = '1.0.1';
|
||||
const SUCCESS_EXIT = 0;
|
||||
const ERROR_EXIT = 1;
|
||||
const SAMPLE_FILE_PATH = '../lib/sample.json';
|
||||
const DEFAULT_FILE_PATH = path.resolve(process.env.HOME, '.pm2');
|
||||
const DEFAULT_LOG_PATH = path.join(DEFAULT_FILE_PATH, 'logs');
|
||||
const DEFAULT_PID_PATH = path.join(DEFAULT_FILE_PATH, 'pids');
|
||||
|
||||
commander.version(VERSION)
|
||||
.option('-v --verbose', 'Display all data')
|
||||
.option('-f --force', 'Force actions')
|
||||
.usage('[cmd] app');
|
||||
|
||||
//
|
||||
// Start command
|
||||
//
|
||||
commander.command('start <part>')
|
||||
.description('start specific part')
|
||||
.action(function(cmd) {
|
||||
|
||||
var data = fs.readFileSync(cmd);
|
||||
var appConf = JSON.parse(data);
|
||||
|
||||
|
||||
if (Array.isArray(appConf)) {
|
||||
(function ex(apps) {
|
||||
if (!apps[0]) return speedList();
|
||||
Satan.executeRemote('prepare', preProcess(apps[0]), function() {
|
||||
apps.shift();
|
||||
return ex(apps);
|
||||
});
|
||||
})(appConf);
|
||||
}
|
||||
else {
|
||||
Satan.executeRemote('findByScript', {script : appConf.script}, function(err, exec) {
|
||||
if (exec && !commander.force) {
|
||||
console.log('Script already launched, add -f option to force re execution');
|
||||
process.exit(ERROR_EXIT);
|
||||
}
|
||||
|
||||
Satan.executeRemote('prepare', preProcess(appConf), function() {
|
||||
console.log('Process launched');
|
||||
speedList();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Stop All processes
|
||||
//
|
||||
commander.command('stop')
|
||||
.description('stop all processes')
|
||||
.action(function(opts, cmd) {
|
||||
console.log('Stopping all processes');
|
||||
|
||||
Satan.executeRemote('stop', {}, function(err, list) {
|
||||
if (err) process.exit(ERROR_EXIT);
|
||||
UX.dispAsTable(list);
|
||||
process.exit(SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
// Sample generate
|
||||
//
|
||||
commander.command('generate <name>')
|
||||
.description('generate sample JSON')
|
||||
.action(function(name) {
|
||||
|
||||
var sample = fs.readFileSync(path.join(__dirname, SAMPLE_FILE_PATH));
|
||||
var dt = sample.toString().replace(/VARIABLE/g, name);
|
||||
var f_name = name + '-pm2.json';
|
||||
|
||||
fs.writeFileSync(path.join(process.env.PWD, f_name), dt);
|
||||
console.info('Sample generated on current folder\n%s :\n', f_name);
|
||||
console.info(dt);
|
||||
process.exit(SUCCESS_EXIT);
|
||||
});
|
||||
|
||||
//
|
||||
// List command
|
||||
//
|
||||
commander.command('list')
|
||||
.description('list all processes')
|
||||
.action(function(opts, cmd) {
|
||||
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
if (err) process.exit(ERROR_EXIT);
|
||||
UX.dispAsTable(list);
|
||||
process.exit(SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
// Monitoring command
|
||||
//
|
||||
commander.command('monit')
|
||||
.description('list all processes')
|
||||
.action(function(opts, cmd) {
|
||||
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
if (err) process.exit(ERROR_EXIT);
|
||||
Monit.init(list);
|
||||
|
||||
function refresh(cb) {
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
setTimeout(function() {
|
||||
Monit.refresh(list);
|
||||
refresh();
|
||||
}, 400);
|
||||
});
|
||||
}
|
||||
refresh();
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
// Log streaming
|
||||
//
|
||||
commander.command('logs')
|
||||
.description('stream logs file')
|
||||
.action(function(opts, cmd) {
|
||||
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
if (err) process.exit(ERROR_EXIT);
|
||||
if (list && list.length == 0) {
|
||||
console.log('No processes online');
|
||||
}
|
||||
list.forEach(function(l) {
|
||||
if (l.opts.fileOutput) Log.stream(l.opts.fileOutput, l.opts.script + ' ' + l.pid);
|
||||
if (l.opts.fileError) Log.stream(l.opts.fileError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
// Kill
|
||||
//
|
||||
commander.command('kill')
|
||||
.description('kill daemon')
|
||||
.action(function() {
|
||||
|
||||
Satan.killDaemon(function(err, res) {
|
||||
if (err) {
|
||||
console.error('Error when killing daemon');
|
||||
process.exit(ERROR_EXIT);
|
||||
}
|
||||
console.info('Daemon killed');
|
||||
process.exit(SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
|
||||
commander.command('*')
|
||||
.action(function() {
|
||||
console.log('\nCommand not found');
|
||||
commander.outputHelp();
|
||||
process.exit(ERROR_EXIT);
|
||||
});
|
||||
|
||||
if (process.argv.length == 2) {
|
||||
commander.outputHelp();
|
||||
process.exit(ERROR_EXIT);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Wait Satan is connected to God to launch parsing
|
||||
//
|
||||
process.on('satan:client:ready', function() {
|
||||
commander.parse(process.argv);
|
||||
});
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Init
|
||||
//
|
||||
(function init() {
|
||||
fs.exists(DEFAULT_FILE_PATH, function(exist) {
|
||||
if (!exist) {
|
||||
fs.mkdirSync(DEFAULT_FILE_PATH);
|
||||
fs.mkdirSync(DEFAULT_LOG_PATH);
|
||||
fs.mkdirSync(DEFAULT_PID_PATH);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
function speedList() {
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
UX.dispAsTable(list);
|
||||
process.exit(SUCCESS_EXIT);
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Resolving path, seing if default ...
|
||||
//
|
||||
function preProcess(app) {
|
||||
app["pm_exec_path"] = path.resolve(process.cwd(), app.script);
|
||||
|
||||
fs.statSync(app.pm_exec_path);
|
||||
|
||||
if (app.fileOutput)
|
||||
app["pm_out_log_path"] = path.resolve(process.cwd(), app.fileOutput);
|
||||
else {
|
||||
if (!app.name) {
|
||||
console.log('You havent specified log path, please specify at least a "name" field in the JSON');
|
||||
process.exit(ERROR_EXIT);
|
||||
}
|
||||
app["pm_out_log_path"] = path.resolve(DEFAULT_LOG_PATH, [app.name, '-out.log'].join(''));
|
||||
app.fileOutput = app["pm_out_log_path"];
|
||||
}
|
||||
|
||||
if (app.fileError)
|
||||
app["pm_err_log_path"] = path.resolve(process.cwd(), app.fileError);
|
||||
else {
|
||||
app["pm_err_log_path"] = path.resolve(DEFAULT_LOG_PATH, [app.name, '-err.log'].join(''));
|
||||
app.fileError = app["pm_err_log_path"];
|
||||
}
|
||||
|
||||
if (app.pidFile)
|
||||
app["pm_pid_path"] = path.resolve(process.cwd(), app.pidFile);
|
||||
else {
|
||||
app["pm_pid_path"] = path.resolve(DEFAULT_PID_PATH, [app.name, '.pid'].join(''));
|
||||
app.pidFile = app["pm_pid_path"];
|
||||
}
|
||||
|
||||
|
||||
fs.existsSync(app.pm_out_log_path);
|
||||
fs.existsSync(app.pm_err_log_path);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
const VERSION = '0.0.1';
|
||||
const SUCCESS_EXIT = 0;
|
||||
const ERROR_EXIT = 1;
|
||||
|
||||
// var logStream = process.stdout;
|
||||
|
||||
@ -18,109 +259,3 @@ const ERROR_EXIT = 1;
|
||||
// ["debug", "info", "warning", "error"].forEach(function(level) {
|
||||
// log[level] = log.bind(null, level);
|
||||
// });
|
||||
|
||||
|
||||
commander.version(VERSION)
|
||||
.option('-v --verbose', 'Display all data')
|
||||
.option('-f --force', 'Force actions')
|
||||
.usage('[cmd] app');
|
||||
|
||||
commander.command('start <part>')
|
||||
.description('start specific part')
|
||||
.action(function(cmd) {
|
||||
|
||||
Satan.executeRemote('prepare', {
|
||||
script : './examples/child.js',
|
||||
fileError : 'logs/errLog.log',
|
||||
fileOutput : 'logs/outLog.log',
|
||||
pidFile : 'pids/child',
|
||||
max : 10,
|
||||
instances : 'max'
|
||||
}, function() {
|
||||
console.log('All process launched');
|
||||
process.exit(1);
|
||||
});
|
||||
//
|
||||
});
|
||||
|
||||
commander.command('stop')
|
||||
.description('stop all processes')
|
||||
.action(function(opts, cmd) {
|
||||
console.log('Stopping all processes');
|
||||
|
||||
|
||||
Satan.executeRemote('stop', {}, function(err, list) {
|
||||
if (err) process.exit(ERROR_EXIT);
|
||||
dispAsTable(list);
|
||||
process.exit(SUCCESS_EXIT);
|
||||
});
|
||||
});
|
||||
|
||||
commander.command('list')
|
||||
.description('list all processes')
|
||||
.action(function(opts, cmd) {
|
||||
|
||||
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
if (err) process.exit(ERROR_EXIT);
|
||||
dispAsTable(list);
|
||||
process.exit(SUCCESS_EXIT);
|
||||
});
|
||||
//
|
||||
});
|
||||
|
||||
// Logs
|
||||
commander.command('monit')
|
||||
.description('list all processes')
|
||||
.action(function(opts, cmd) {
|
||||
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
if (err) process.exit(ERROR_EXIT);
|
||||
Monit.init(list);
|
||||
|
||||
function refresh(cb) {
|
||||
Satan.executeRemote('list', {}, function(err, list) {
|
||||
setTimeout(function() {
|
||||
Monit.refresh(list);
|
||||
refresh();
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
refresh();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
commander.command('launch')
|
||||
.description('manual launch of God')
|
||||
.action(function(cmd) {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
//
|
||||
// Wait Satan is connected to God to launch parsing
|
||||
//
|
||||
process.on('satan:ready', function() {
|
||||
commander.parse(process.argv);
|
||||
});
|
||||
|
||||
function dispAsTable(list) {
|
||||
var table = new Table({ head: ["Script", "id", "PID","status", "memory"] });
|
||||
list.forEach(function(l) {
|
||||
var u = l.opts.script;
|
||||
var obj = {};
|
||||
|
||||
obj[l.opts.script] = [
|
||||
l.pm_id,
|
||||
l.pid,
|
||||
l.status,
|
||||
l.monit ? l.monit.memory : ''
|
||||
];
|
||||
|
||||
table.push(obj);
|
||||
});
|
||||
|
||||
console.log(table.toString());
|
||||
}
|
||||
|
||||
@ -5,13 +5,13 @@
|
||||
(function child_wrapper() {
|
||||
var fs = require('fs');
|
||||
var worker = require('cluster').worker;
|
||||
|
||||
|
||||
var outFile = process.env.pm_outFile;
|
||||
var errFile = process.env.pm_errFile;
|
||||
var pmId = process.env.pm_id;
|
||||
var pidFile = [process.env.pm_pidFile, pmId, '.pid'].join('');
|
||||
var pidFile = [process.env.pm_pidFile, pmId].join('');
|
||||
var script = process.env.pm_script;
|
||||
|
||||
|
||||
fs.writeFileSync(pidFile, process.pid);
|
||||
|
||||
var stdout = fs.createWriteStream(outFile, { flags : 'a' });
|
||||
@ -19,13 +19,13 @@
|
||||
|
||||
process.stderr.write = (function(write) {
|
||||
return function(string, encoding, fd) {
|
||||
stderr.write(string);
|
||||
stdout.write(JSON.stringify({msg :string, date : (new Date()).toISOString()}));
|
||||
};
|
||||
})(process.stderr.write);
|
||||
|
||||
|
||||
process.stdout.write = (function(write) {
|
||||
return function(string, encoding, fd) {
|
||||
stdout.write(string);
|
||||
stderr.write(string);
|
||||
};
|
||||
})(process.stdout.write);
|
||||
|
||||
@ -35,16 +35,16 @@
|
||||
});
|
||||
|
||||
require(script);
|
||||
|
||||
|
||||
|
||||
|
||||
// var domain = require('domain').create();
|
||||
|
||||
// domain.run(function() {
|
||||
// require(script);
|
||||
|
||||
// domain.run(function() {
|
||||
// require(script);
|
||||
// });
|
||||
|
||||
|
||||
// domain.on('error', function(e) {
|
||||
// stderr.write(e);
|
||||
// });
|
||||
|
||||
|
||||
})();
|
||||
|
||||
@ -1,19 +1,8 @@
|
||||
|
||||
var cluster = require('cluster');
|
||||
var http = require('http');
|
||||
var numCPUs = require('os').cpus().length;
|
||||
//var worker = require('cluster').worker;
|
||||
|
||||
|
||||
console.log(process.env.NODE_UNIQUE_ID, cluster.isWorker);
|
||||
|
||||
var i = 0;
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
res.writeHead(200);
|
||||
res.end("hello world\n" + i++);
|
||||
res.writeHead(200);
|
||||
res.end("hello world\n" + i++);
|
||||
}).listen(8000);
|
||||
|
||||
// setTimeout(function() {
|
||||
// process.exit(1);
|
||||
// }, 2000);
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
|
||||
setInterval(function() {
|
||||
console.log('ok');
|
||||
console.error('merde');
|
||||
}, 500);
|
||||
|
||||
setTimeout(function() {
|
||||
throw new Error('eh merde');
|
||||
}, 3000);
|
||||
console.log('ok');
|
||||
}, 800);
|
||||
|
||||
9
examples/echokill.js
Normal file
9
examples/echokill.js
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
setInterval(function() {
|
||||
console.log('ok');
|
||||
}, 800);
|
||||
|
||||
setTimeout(function() {
|
||||
process.exit(-1);
|
||||
}, 3000);
|
||||
353
god.js
353
god.js
@ -8,218 +8,205 @@ var async = require('async');
|
||||
var path = require('path');
|
||||
|
||||
cluster.setupMaster({
|
||||
exec : path.resolve('child_wrapper.js')
|
||||
exec : path.resolve('child_wrapper.js')
|
||||
});
|
||||
|
||||
var God = module.exports = {
|
||||
next_id : 0,
|
||||
clusters_db : {}
|
||||
next_id : 0,
|
||||
clusters_db : {}
|
||||
};
|
||||
|
||||
//
|
||||
// Init
|
||||
//
|
||||
(function initEngine() {
|
||||
cluster.on('online', function(clu) {
|
||||
console.log("%s - id%d worker online",
|
||||
clu.opts.script,
|
||||
clu.pm_id);
|
||||
God.clusters_db[clu.pm_id].status = 'online';
|
||||
});
|
||||
|
||||
cluster.on('exit', function(clu, code, signal) {
|
||||
console.log('Script %s %d exited code %d',
|
||||
clu.opts.script,
|
||||
clu.pm_id,
|
||||
code);
|
||||
cluster.on('online', function(clu) {
|
||||
console.log("%s - id%d worker online",
|
||||
clu.opts.script,
|
||||
clu.pm_id);
|
||||
God.clusters_db[clu.pm_id].status = 'online';
|
||||
});
|
||||
|
||||
cluster.on('exit', function(clu, code, signal) {
|
||||
console.log('Script %s %d exited code %d',
|
||||
clu.opts.script,
|
||||
clu.pm_id,
|
||||
code);
|
||||
|
||||
God.clusters_db[clu.pm_id].status = 'starting';
|
||||
|
||||
if (clu.opts.max !== undefined) {
|
||||
if (clu.opts.max <= 0) {
|
||||
God.clusters_db[clu.pm_id].status = 'stopped';
|
||||
delete God.clusters_db[clu.pm_id];
|
||||
return ;
|
||||
}
|
||||
else clu.opts.max -= 1;
|
||||
}
|
||||
|
||||
delete God.clusters_db[clu.pm_id];
|
||||
execute(clu.opts);
|
||||
|
||||
});
|
||||
|
||||
|
||||
God.clusters_db[clu.pm_id].status = 'starting';
|
||||
|
||||
//delete God.clusters_db[clu.pm_id];
|
||||
|
||||
if (clu.opts.max !== undefined) {
|
||||
if (clu.opts.max <= 0) {
|
||||
God.clusters_db[clu.pm_id].status = 'stopped';
|
||||
return ;
|
||||
}
|
||||
else clu.opts.max -= 1;
|
||||
}
|
||||
execute(clu.opts);
|
||||
});
|
||||
})();
|
||||
|
||||
God.stopAll = function(cb) {
|
||||
var pros = God.getFormatedProcesses();
|
||||
var l = pros.length;
|
||||
|
||||
(function ex(processes, i) {
|
||||
if (i <= -1) return cb(null, God.getFormatedProcesses());
|
||||
if (processes[i].state == 'stopped') return ex(processes, i - 1);
|
||||
return God.stopProcess(processes[i], function() {
|
||||
ex(processes, i - 1);
|
||||
});
|
||||
})(pros, l - 1);
|
||||
};
|
||||
|
||||
God.getProcesses = function() {
|
||||
return God.clusters_db;
|
||||
};
|
||||
|
||||
God.getMonitorData = function(cb) {
|
||||
var processes = God.getFormatedProcesses();
|
||||
var arr = [];
|
||||
|
||||
function ex(i) {
|
||||
if (i <= -1) return cb(null, arr);
|
||||
var pro = processes[i];
|
||||
|
||||
usage.lookup(pro.pid, { keepHistory : true }, function(err, res) {
|
||||
pro['monit'] = res;
|
||||
arr.push(pro);
|
||||
return ex(i - 1);
|
||||
});
|
||||
};
|
||||
|
||||
ex(processes.length - 1);
|
||||
};
|
||||
|
||||
God.getFormatedProcesses = function() {
|
||||
var db = God.clusters_db;
|
||||
var arr = [];
|
||||
|
||||
for (var key in db) {
|
||||
if (db[key])
|
||||
arr.push({
|
||||
pid : db[key].process.pid,
|
||||
opts : db[key].opts,
|
||||
pm_id : db[key].pm_id,
|
||||
status : db[key].status
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
God.findByScript = function(script) {
|
||||
var db = God.clusters_db;
|
||||
|
||||
for (var key in db) {
|
||||
if (db[key].opts.script == script) {
|
||||
return db[key].opts;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
God.checkProcess = function(pid) {
|
||||
if (!pid) return false;
|
||||
|
||||
try {
|
||||
// Sending 0 signal do not kill the process
|
||||
process.kill(pid, 0);
|
||||
return true;
|
||||
}
|
||||
catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
God.startProcess = function(clu, cb) {
|
||||
God.clusters_db[clu.pm_id].opts.max = 99;
|
||||
execute(God.clusters_db[clu.pm_id].opts, cb);
|
||||
};
|
||||
|
||||
God.startProcessId = function(id, cb) {
|
||||
if (God.clusters_db[id] === undefined)
|
||||
return cb({ msg : "PM ID unknown"}, {});
|
||||
if (God.clusters_db[id].status == "online")
|
||||
return cb({ msg : "Process already online"}, {});
|
||||
God.clusters_db[id].opts.max = 99;
|
||||
return execute(God.clusters_db[id].opts, cb);
|
||||
};
|
||||
|
||||
God.stopProcess = function(clu, cb) {
|
||||
God.clusters_db[clu.pm_id].opts.max = 0;
|
||||
process.kill(God.clusters_db[clu.pm_id].process.pid);
|
||||
God.clusters_db[clu.pm_id].process.pid = 0;
|
||||
setTimeout(cb, 200);
|
||||
};
|
||||
|
||||
God.stopProcessId = function(id, cb) {
|
||||
God.clusters_db[id].opts.max = 0;
|
||||
process.kill(God.clusters_db[id].process.pid);
|
||||
God.clusters_db[id].process.pid = 0;
|
||||
setTimeout(cb, 200);
|
||||
};
|
||||
|
||||
//
|
||||
// Public method
|
||||
//
|
||||
God.prepare = function(opts, cb) {
|
||||
if (opts.instances) {
|
||||
// instances "max" have been setted
|
||||
var arr = [];
|
||||
(function ex(i) {
|
||||
if (i <= 0) {
|
||||
if (cb != null) return cb(null, arr);
|
||||
return true;
|
||||
}
|
||||
return execute(JSON.parse(JSON.stringify(opts)), function(err, clu) { // deep copy
|
||||
arr.push(clu);
|
||||
ex(i - 1);
|
||||
});
|
||||
})(numCPUs);
|
||||
}
|
||||
else return execute(opts, cb);
|
||||
};
|
||||
|
||||
God.stopAll = function(cb) {
|
||||
var pros = God.getFormatedProcesses();
|
||||
var l = pros.length;
|
||||
|
||||
(function ex(processes, i) {
|
||||
if (i <= -1) return cb(null, God.getFormatedProcesses());
|
||||
if (processes[i].state == 'stopped')
|
||||
return ex(processes, i - 1);
|
||||
return God.stopProcess(processes[i], function() {
|
||||
ex(processes, i - 1);
|
||||
});
|
||||
})(pros, l - 1);
|
||||
};
|
||||
|
||||
God.getProcesses = function() {
|
||||
return God.clusters_db;
|
||||
};
|
||||
|
||||
God.getMonitorData = function(cb) {
|
||||
var processes = God.getFormatedProcesses();
|
||||
if (opts.instances) {
|
||||
// instances "max" have been setted
|
||||
// multi fork depending on number of cpus
|
||||
var arr = [];
|
||||
|
||||
function ex(i) {
|
||||
if (i <= -1) return cb(null, arr);
|
||||
var pro = processes[i];
|
||||
usage.lookup(pro.pid, { keepHistory : true }, function(err, res) {
|
||||
pro['monit'] = res;
|
||||
arr.push(pro);
|
||||
return ex(i - 1);
|
||||
});
|
||||
};
|
||||
|
||||
ex(processes.length - 1);
|
||||
};
|
||||
|
||||
God.getFormatedProcesses = function() {
|
||||
var db = God.clusters_db;
|
||||
var arr = [];
|
||||
|
||||
for (var key in db) {
|
||||
if (db[key])
|
||||
arr.push({
|
||||
pid : db[key].process.pid,
|
||||
opts : db[key].opts,
|
||||
pm_id : db[key].pm_id,
|
||||
status : db[key].status
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
God.checkProcess = function(pid) {
|
||||
if (!pid) return false;
|
||||
|
||||
try {
|
||||
// Sending 0 signal do not kill the process
|
||||
process.kill(pid, 0);
|
||||
(function ex(i) {
|
||||
if (i <= 0) {
|
||||
if (cb != null) return cb(null, arr);
|
||||
return true;
|
||||
}
|
||||
catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
God.startProcess = function(clu, cb) {
|
||||
God.clusters_db[clu.pm_id].opts.max = 99;
|
||||
execute(God.clusters_db[clu.pm_id].opts);
|
||||
};
|
||||
|
||||
God.stopProcess = function(clu, cb) {
|
||||
God.clusters_db[clu.pm_id].opts.max = 0;
|
||||
process.kill(God.clusters_db[clu.pm_id].process.pid);
|
||||
God.clusters_db[clu.pm_id].process.pid = 0;
|
||||
setTimeout(cb, 200);
|
||||
}
|
||||
return execute(JSON.parse(JSON.stringify(opts)), function(err, clu) { // deep copy
|
||||
arr.push(clu);
|
||||
ex(i - 1);
|
||||
});
|
||||
})(numCPUs);
|
||||
}
|
||||
else return execute(opts, cb);
|
||||
};
|
||||
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
function execute(opts, cb) {
|
||||
var id;
|
||||
var id, exec_path, out_log_path, err_log_path, pid_path;
|
||||
|
||||
if (opts.pm_id)
|
||||
id = opts.pm_id;
|
||||
else {
|
||||
id = God.next_id;
|
||||
God.next_id += 1;
|
||||
}
|
||||
|
||||
var clu = cluster.fork({
|
||||
pm_script : opts.script,
|
||||
pm_errFile : opts.fileError,
|
||||
pm_outFile : opts.fileOutput,
|
||||
pm_pidFile : opts.pidFile,
|
||||
pm_id : id
|
||||
});
|
||||
|
||||
opts['pm_id'] = id;
|
||||
clu['pm_id'] = id;
|
||||
clu['opts'] = opts;
|
||||
clu['status'] = 'launching';
|
||||
id = God.next_id;
|
||||
God.next_id += 1;
|
||||
|
||||
|
||||
God.clusters_db[clu.pm_id] = clu;
|
||||
var clu = cluster.fork({
|
||||
pm_script : opts["pm_exec_path"],
|
||||
pm_errFile : opts["pm_err_log_path"],
|
||||
pm_outFile : opts["pm_out_log_path"],
|
||||
pm_pidFile : opts["pm_pid_path"],
|
||||
pm_id : id
|
||||
});
|
||||
|
||||
clu.once('online', function() {
|
||||
God.clusters_db[clu.pm_id].status = 'online';
|
||||
if (cb) return cb(null, clu);
|
||||
return true;
|
||||
});
|
||||
opts['pm_id'] = id;
|
||||
clu['pm_id'] = id;
|
||||
clu['opts'] = opts;
|
||||
clu['status'] = 'launching';
|
||||
|
||||
// Should fix it
|
||||
// DONT use it for now !!
|
||||
clu.start = function(cb) {
|
||||
var self = this;
|
||||
God.clusters_db[id] = clu;
|
||||
|
||||
execute(this.opts, function(err, clu) {
|
||||
cb(err, clu);
|
||||
});
|
||||
};
|
||||
|
||||
clu.stop = function(cb) {
|
||||
clu.once('online', function() {
|
||||
God.clusters_db[id].status = 'online';
|
||||
if (cb) return cb(null, clu);
|
||||
return true;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return clu;
|
||||
return clu;
|
||||
}
|
||||
|
||||
|
||||
// (function exec() {
|
||||
|
||||
// God.prepare({
|
||||
// script : './examples/child.js',
|
||||
// fileError : 'logs/errLog.log',
|
||||
// fileOutput : 'logs/outLog.log',
|
||||
// pidFile : 'pids/child',
|
||||
// max : 2,
|
||||
// instances : 'max'
|
||||
// });
|
||||
|
||||
// God.prepare({
|
||||
// script : './examples/echo.js',
|
||||
// fileError : 'logs/echoErr.log',
|
||||
// fileOutput : 'logs/echoLog.log',
|
||||
// pidFile : 'pids/child'
|
||||
// });
|
||||
|
||||
// setInterval(function() {
|
||||
// //console.log(God.clusters_db);
|
||||
// God.getMonitorData(function(dt) {
|
||||
// console.log(dt);
|
||||
// });
|
||||
// }, 1000);
|
||||
// })();
|
||||
|
||||
85
lib/Log.js
Normal file
85
lib/Log.js
Normal file
@ -0,0 +1,85 @@
|
||||
//
|
||||
// Display a file in streaming
|
||||
//
|
||||
var fs = require('fs');
|
||||
|
||||
var colors = [
|
||||
'\x1B[34m',
|
||||
'\x1B[36m',
|
||||
'\x1B[32m',
|
||||
'\x1B[35m',
|
||||
'\x1B[31m',
|
||||
'\x1B[30m',
|
||||
'\x1B[90m',
|
||||
'\x1B[33m',
|
||||
'\x1B[34m',
|
||||
'\x1B[36m',
|
||||
'\x1B[32m',
|
||||
'\x1B[35m',
|
||||
'\x1B[31m',
|
||||
'\x1B[30m',
|
||||
'\x1B[90m',
|
||||
'\x1B[33m'
|
||||
];
|
||||
|
||||
var gl_idx = 0;
|
||||
var db = [];
|
||||
|
||||
var Log = module.exports = {};
|
||||
|
||||
Log.stream = function(path, title) {
|
||||
if (title === undefined)
|
||||
title = gl_idx;
|
||||
|
||||
try {
|
||||
var currSize = 0;
|
||||
if (fs.statSync(path).size > 1000)
|
||||
currSize = fs.statSync(path).size - 500;
|
||||
} catch(e) {
|
||||
if (e.code == 'ENOENT')
|
||||
console.log('%s with %s file not found', title, path);
|
||||
return false;
|
||||
}
|
||||
|
||||
var odb = db[title] = {color : colors[gl_idx++], l : 0};
|
||||
|
||||
fs.watch(path, function(ev, filename) {
|
||||
if (ev == 'rename')
|
||||
return console.error('Renaming file ?');
|
||||
|
||||
fs.stat(path, function(err, stat) {
|
||||
var prevSize = stat.size;
|
||||
|
||||
if (currSize > prevSize) return true;
|
||||
|
||||
var rstream = fs.createReadStream(path, {
|
||||
encoding : 'utf8',
|
||||
start : currSize,
|
||||
end : prevSize
|
||||
});
|
||||
|
||||
rstream.on('data', function(data) {
|
||||
print_data(odb, title, data);
|
||||
});
|
||||
|
||||
currSize = stat.size;
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Privates
|
||||
//
|
||||
function print_data(odb, title, data) {
|
||||
var lines = data.split('\n');
|
||||
|
||||
lines.forEach(function(l) {
|
||||
if (l)
|
||||
console.log(odb.color + '[%s (l%d)]\x1B[39m %s',
|
||||
title,
|
||||
odb.l++,
|
||||
l);
|
||||
});
|
||||
};
|
||||
26
lib/cli-ux.js
Normal file
26
lib/cli-ux.js
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
var Table = require('cli-table');
|
||||
|
||||
var UX = module.exports = {};
|
||||
|
||||
UX.dispAsTable = function(list) {
|
||||
var table = new Table({ head: ["Script", "id", "PID","status", "memory", "out logs", "err logs", "full path"] });
|
||||
list.forEach(function(l) {
|
||||
var u = l.opts.script;
|
||||
var obj = {};
|
||||
|
||||
obj[l.opts.script] = [
|
||||
l.pm_id,
|
||||
l.pid,
|
||||
l.status,
|
||||
l.monit ? l.monit.memory : '',
|
||||
l.opts.fileOutput,
|
||||
l.opts.fileError,
|
||||
l.opts.pm_exec_path
|
||||
];
|
||||
|
||||
table.push(obj);
|
||||
});
|
||||
|
||||
console.log(table.toString());
|
||||
}
|
||||
72
lib/logger.js
Normal file
72
lib/logger.js
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// Display a file in streaming
|
||||
//
|
||||
var fs = require('fs');
|
||||
|
||||
var colors = [
|
||||
'\x1B[34m',
|
||||
'\x1B[36m',
|
||||
'\x1B[32m',
|
||||
'\x1B[35m',
|
||||
'\x1B[31m',
|
||||
'\x1B[30m',
|
||||
'\x1B[90m',
|
||||
'\x1B[33m'
|
||||
];
|
||||
|
||||
var gl_idx = 0;
|
||||
var db = [];
|
||||
|
||||
var Log = module.exports = {};
|
||||
|
||||
Log.stream_log = function(title, path) {
|
||||
try {
|
||||
var currSize = 0; //fs.statSync(path).size;
|
||||
} catch(e) {
|
||||
if (e.code == 'ENOENT')
|
||||
console.log('%s with %s file not found', title, path);
|
||||
return false;
|
||||
}
|
||||
|
||||
var odb = db[title] = {color : colors[gl_idx++], l : 0};
|
||||
|
||||
fs.watch(path, function(ev, filename) {
|
||||
if (ev == 'rename')
|
||||
return console.error('Renaming file ?');
|
||||
|
||||
fs.stat(path, function(err, stat) {
|
||||
var prevSize = stat.size;
|
||||
|
||||
if (currSize > prevSize) return true;
|
||||
|
||||
var rstream = fs.createReadStream(path, {
|
||||
encoding : 'utf8',
|
||||
start : currSize,
|
||||
end : prevSize
|
||||
});
|
||||
|
||||
rstream.on('data', function(data) {
|
||||
print_data(odb, title, data);
|
||||
});
|
||||
|
||||
currSize = stat.size;
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Privates
|
||||
//
|
||||
function print_data(odb, title, data) {
|
||||
var lines = data.split('\n');
|
||||
|
||||
lines.forEach(function(l) {
|
||||
if (l)
|
||||
console.log(odb.color + '[%s (l%d)]\x1B[39m %s',
|
||||
title,
|
||||
odb.l++,
|
||||
l);
|
||||
});
|
||||
};
|
||||
147
lib/monit.js
147
lib/monit.js
@ -3,92 +3,89 @@ var multimeter = require('multimeter');
|
||||
|
||||
var bars = {};
|
||||
|
||||
var Monit = module.exports = {
|
||||
init : init,
|
||||
refresh : refresh
|
||||
};
|
||||
var Monit = module.exports = {};
|
||||
|
||||
function init(processes) {
|
||||
Monit.multi = multimeter(process);
|
||||
Monit.init = function(processes) {
|
||||
if (processes === undefined) throw new Error('No processes passed to init');
|
||||
Monit.multi = multimeter(process);
|
||||
|
||||
Monit.multi.on('^C', process.exit);
|
||||
Monit.multi.charm.reset();
|
||||
Monit.multi.on('^C', process.exit);
|
||||
Monit.multi.charm.reset();
|
||||
|
||||
Monit.multi.write('PM2 monitoring :\n\n');
|
||||
Monit.multi.write('PM2 monitoring :\n\n');
|
||||
|
||||
processes.forEach(function(proc, i) {
|
||||
if (proc.status == 'stopped') return ;
|
||||
Monit.multi.write(proc.opts.script + ' [' + proc.pid + '] ' + ' \n\n');
|
||||
processes.forEach(function(proc, i) {
|
||||
if (proc.status == 'stopped') return ;
|
||||
Monit.multi.write(proc.opts.script + ' [' + proc.pid + '] ' + ' \n\n');
|
||||
|
||||
var bar_cpu = Monit.multi(40, (i * 2) + 3 + i, {
|
||||
width: 30,
|
||||
solid: {
|
||||
text: '|',
|
||||
foreground: 'white',
|
||||
background: 'blue'
|
||||
},
|
||||
empty: {
|
||||
text: ' '
|
||||
}
|
||||
});
|
||||
|
||||
var bar_memory = Monit.multi(40, (i * 2) + 4 + i, {
|
||||
width: 30,
|
||||
solid: {
|
||||
text: '|',
|
||||
foreground: 'white',
|
||||
background: 'red'
|
||||
},
|
||||
empty: {
|
||||
text: ' '
|
||||
}
|
||||
});
|
||||
|
||||
bar_cpu.percent(proc.monit.cpu);
|
||||
bar_memory.ratio(proc.monit.memory,
|
||||
200000000,
|
||||
bytesToSize(proc.monit.memory, 3));
|
||||
bars[proc.pid] = {};
|
||||
bars[proc.pid].memory = bar_memory;
|
||||
bars[proc.pid].cpu = bar_cpu;
|
||||
Monit.multi.write('\n');
|
||||
var bar_cpu = Monit.multi(40, (i * 2) + 3 + i, {
|
||||
width: 30,
|
||||
solid: {
|
||||
text: '|',
|
||||
foreground: 'white',
|
||||
background: 'blue'
|
||||
},
|
||||
empty: {
|
||||
text: ' '
|
||||
}
|
||||
});
|
||||
|
||||
var bar_memory = Monit.multi(40, (i * 2) + 4 + i, {
|
||||
width: 30,
|
||||
solid: {
|
||||
text: '|',
|
||||
foreground: 'white',
|
||||
background: 'red'
|
||||
},
|
||||
empty: {
|
||||
text: ' '
|
||||
}
|
||||
});
|
||||
|
||||
bar_cpu.percent(proc.monit.cpu);
|
||||
bar_memory.ratio(proc.monit.memory,
|
||||
200000000,
|
||||
bytesToSize(proc.monit.memory, 3));
|
||||
bars[proc.pid] = {};
|
||||
bars[proc.pid].memory = bar_memory;
|
||||
bars[proc.pid].cpu = bar_cpu;
|
||||
Monit.multi.write('\n');
|
||||
});
|
||||
}
|
||||
|
||||
function refresh(dt) {
|
||||
if (Object.keys(bars).length == 0) {
|
||||
Monit.multi.write('No online process to monitor\n');
|
||||
process.exit(1);
|
||||
Monit.refresh = function(dt) {
|
||||
if (Object.keys(bars).length == 0) {
|
||||
Monit.multi.write('No online process to monitor\n');
|
||||
process.exit(1);
|
||||
}
|
||||
dt.forEach(function(proc, i) {
|
||||
if (proc && proc.monit && bars[proc.pid]) {
|
||||
|
||||
bars[proc.pid].cpu.percent(proc.monit.cpu);
|
||||
bars[proc.pid].memory.ratio(proc.monit.memory,
|
||||
200000000,
|
||||
bytesToSize(proc.monit.memory, 3));
|
||||
}
|
||||
dt.forEach(function(proc, i) {
|
||||
if (proc && proc.monit && bars[proc.pid]) {
|
||||
|
||||
bars[proc.pid].cpu.percent(proc.monit.cpu);
|
||||
bars[proc.pid].memory.ratio(proc.monit.memory,
|
||||
200000000,
|
||||
bytesToSize(proc.monit.memory, 3));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function bytesToSize(bytes, precision) {
|
||||
var kilobyte = 1024;
|
||||
var megabyte = kilobyte * 1024;
|
||||
var gigabyte = megabyte * 1024;
|
||||
var terabyte = gigabyte * 1024;
|
||||
var kilobyte = 1024;
|
||||
var megabyte = kilobyte * 1024;
|
||||
var gigabyte = megabyte * 1024;
|
||||
var terabyte = gigabyte * 1024;
|
||||
|
||||
if ((bytes >= 0) && (bytes < kilobyte)) {
|
||||
return bytes + ' B';
|
||||
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
|
||||
return (bytes / kilobyte).toFixed(precision) + ' KB';
|
||||
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
|
||||
return (bytes / megabyte).toFixed(precision) + ' MB';
|
||||
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
|
||||
return (bytes / gigabyte).toFixed(precision) + ' GB';
|
||||
} else if (bytes >= terabyte) {
|
||||
return (bytes / terabyte).toFixed(precision) + ' TB';
|
||||
} else {
|
||||
return bytes + ' B';
|
||||
}
|
||||
if ((bytes >= 0) && (bytes < kilobyte)) {
|
||||
return bytes + ' B';
|
||||
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
|
||||
return (bytes / kilobyte).toFixed(precision) + ' KB';
|
||||
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
|
||||
return (bytes / megabyte).toFixed(precision) + ' MB';
|
||||
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
|
||||
return (bytes / gigabyte).toFixed(precision) + ' GB';
|
||||
} else if (bytes >= terabyte) {
|
||||
return (bytes / terabyte).toFixed(precision) + ' TB';
|
||||
} else {
|
||||
return bytes + ' B';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
7
lib/sample.json
Normal file
7
lib/sample.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"path" : "VARIABLE.js",
|
||||
"fileError" : "out-VARIABLE.log",
|
||||
"fileOutput" : "err-VARIABLE.log",
|
||||
"pidFile" : "exec-VARIABLE.pid",
|
||||
"options": [""]
|
||||
}
|
||||
48
lib/web-interface.js
Normal file
48
lib/web-interface.js
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
try {
|
||||
var express = require('express');
|
||||
}
|
||||
catch (e) {
|
||||
console.error('[GOD] In order to use the web interface, Install express');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var http = require('http');
|
||||
var os = require('os');
|
||||
var Satan = require('../satan.js');
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(express.errorHandler());
|
||||
app.use(express.logger('dev'));
|
||||
|
||||
app.get('/', function(req, res) {
|
||||
var json = [];
|
||||
|
||||
Satan.executeRemote('list', {}, function(err, data_proc) {
|
||||
|
||||
// Computer API point
|
||||
var data = {
|
||||
processes: data_proc,
|
||||
system_info: { hostname: os.hostname(),
|
||||
uptime: os.uptime()
|
||||
},
|
||||
monit: { loadavg: os.loadavg(),
|
||||
total_mem: os.totalmem(),
|
||||
free_mem: os.freemem(),
|
||||
cpu: os.cpus(),
|
||||
interfaces: os.networkInterfaces()
|
||||
}
|
||||
};
|
||||
|
||||
return res.send(data);
|
||||
});
|
||||
});
|
||||
|
||||
var server = http.createServer(app);
|
||||
|
||||
server.listen(4000, function() {
|
||||
console.log("Web server enabled on port 4000");
|
||||
});
|
||||
@ -1,53 +0,0 @@
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
Error: eh merde
|
||||
at Object._onTimeout (/home/tknew/WiredCraft/api.devo.ps/manager/experimental/examples/echo.js:8:11)
|
||||
at Timer.list.ontimeout (timers.js:101:19)merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
Error: eh merde
|
||||
at Object._onTimeout (/home/tknew/WiredCraft/api.devo.ps/manager/experimental/examples/echo.js:8:11)
|
||||
at Timer.list.ontimeout (timers.js:101:19)merde
|
||||
Error: eh merde
|
||||
at Object._onTimeout (/home/tknew/WiredCraft/api.devo.ps/manager/experimental/examples/echo.js:8:11)
|
||||
at Timer.list.ontimeout (timers.js:101:19)merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
Error: eh merde
|
||||
at Object._onTimeout (/home/tknew/WiredCraft/api.devo.ps/manager/experimental/examples/echo.js:8:11)
|
||||
at Timer.list.ontimeout (timers.js:101:19)merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
merde
|
||||
Error: eh merde
|
||||
at Object._onTimeout (/home/tknew/WiredCraft/api.devo.ps/manager/experimental/examples/echo.js:8:11)
|
||||
at Timer.list.ontimeout (timers.js:101:19)
|
||||
@ -1,42 +0,0 @@
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
462717
logs/errLog.log
462717
logs/errLog.log
File diff suppressed because it is too large
Load Diff
1082
logs/outLog.log
1082
logs/outLog.log
File diff suppressed because it is too large
Load Diff
@ -258,4 +258,4 @@ function findScript(script, cb) {
|
||||
forever.getAllProcesses(function(dt) {
|
||||
cb(forever.findByScript(script, dt));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
99
package.json
99
package.json
@ -1,46 +1,57 @@
|
||||
{
|
||||
"name": "god",
|
||||
"preferGlobal": "true",
|
||||
"version": "0.4.0",
|
||||
"description": "Manage processes with JSON files, reload, monitor, show logs and manage process programaticaly",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "NODE_ENV=test ./node_modules/mocha/bin/mocha test ; bash test/cli-test.sh",
|
||||
"froze": "npm shrinkwrap"
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
"fault tolerant",
|
||||
"sysadmin",
|
||||
"tools",
|
||||
"monitoring",
|
||||
"process manager",
|
||||
"forever",
|
||||
"process configuration"],
|
||||
"bin": {
|
||||
"pm2": "./bin/cli"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": "*",
|
||||
"cli-table" : "*",
|
||||
"multimeter": "*",
|
||||
"usage" : "*",
|
||||
"watch": "*",
|
||||
"axon-rpc" : "*",
|
||||
"axon" : "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "1.x",
|
||||
"should": "1.x"
|
||||
},
|
||||
"repository": "",
|
||||
"author": {
|
||||
"name": "AS"
|
||||
},
|
||||
"contributors": [{
|
||||
"name": "Strzelewicz Alexandre",
|
||||
"email": "strzelewicz.alexandre@gmail.com",
|
||||
"website": "http://apps.hemca.com"
|
||||
}],
|
||||
"license": "MIT"
|
||||
"name": "god",
|
||||
"preferGlobal": "true",
|
||||
"version": "0.4.0",
|
||||
"os" : [ "!win32" ],
|
||||
"engines" : {
|
||||
"node" : ">=0.8"
|
||||
},
|
||||
"homepage" : "http://unitech.io/",
|
||||
"description": "Manage apps with a declarative approach (JSON). Clusterize network apps in 0 lines of code.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "NODE_ENV=test ./node_modules/mocha/bin/mocha test",
|
||||
"testc": "NODE_ENV=test ./node_modules/mocha/bin/mocha test ; bash ./test/cli.sh",
|
||||
"froze": "npm shrinkwrap"
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
"fault tolerant",
|
||||
"sysadmin",
|
||||
"tools",
|
||||
"monitoring",
|
||||
"process manager",
|
||||
"forever",
|
||||
"process configuration",
|
||||
"clustering",
|
||||
"cluster cli",
|
||||
"cluster"
|
||||
],
|
||||
"bin": {
|
||||
"pm2": "./bin/god"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": "*",
|
||||
"cli-table" : "*",
|
||||
"multimeter": "git://github.com/Alexandre-Strzelewicz/node-multimeter.git",
|
||||
"usage" : "*",
|
||||
"watch": "*",
|
||||
"axon-rpc" : "*",
|
||||
"axon" : "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "1.x",
|
||||
"should": "1.x",
|
||||
"better-assert" : "*"
|
||||
},
|
||||
"repository": "",
|
||||
"author": {
|
||||
"name": "AS"
|
||||
},
|
||||
"contributors": [{
|
||||
"name": "Strzelewicz Alexandre",
|
||||
"email": "strzelewicz.alexandre@gmail.com",
|
||||
"url": "http://apps.hemca.com"
|
||||
}],
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
7554
|
||||
@ -1 +0,0 @@
|
||||
7556
|
||||
@ -1 +0,0 @@
|
||||
18217
|
||||
@ -1 +0,0 @@
|
||||
18220
|
||||
@ -1 +0,0 @@
|
||||
15718
|
||||
@ -1 +0,0 @@
|
||||
7560
|
||||
@ -1 +0,0 @@
|
||||
7563
|
||||
@ -1 +0,0 @@
|
||||
18178
|
||||
@ -1 +0,0 @@
|
||||
18180
|
||||
@ -1 +0,0 @@
|
||||
18184
|
||||
@ -1 +0,0 @@
|
||||
18187
|
||||
@ -1 +0,0 @@
|
||||
18212
|
||||
@ -1 +0,0 @@
|
||||
18214
|
||||
257
satan.js
257
satan.js
@ -4,149 +4,184 @@ var axon = require('axon');
|
||||
var rep = axon.socket('rep');
|
||||
var req = axon.socket('req');
|
||||
var debug = require('debug')('god:satan');
|
||||
var God = require('./god.js');
|
||||
var events = require("events");
|
||||
var util = require("util");
|
||||
|
||||
const SATAN_PORT = 66666;
|
||||
|
||||
var Satan = module.exports = {
|
||||
var Satan = module.exports = {};
|
||||
|
||||
//
|
||||
// Code switcher
|
||||
//
|
||||
Satan.onReady = function() {
|
||||
(function init() {
|
||||
if (process.env.DAEMON) {
|
||||
Satan.remoteWrapper();
|
||||
}
|
||||
else {
|
||||
Satan.pingDaemon(function(ab) {
|
||||
if (ab == false)
|
||||
return Satan.launchDaemon(Satan.launchRPC);
|
||||
return Satan.launchRPC();
|
||||
});
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
//
|
||||
// The code that will be executed on the next process
|
||||
// Here it exposes God methods
|
||||
//
|
||||
Satan.remoteWrapper = function() {
|
||||
// Send ready message to Satan Client
|
||||
process.send({
|
||||
online : true, success : true, pid : process.pid
|
||||
});
|
||||
|
||||
var server = new rpc.Server(rep);
|
||||
|
||||
rep.bind(66666);
|
||||
|
||||
server.expose({
|
||||
prepare : function(opts, fn) {
|
||||
God.prepare(opts, function(err, clu) {
|
||||
fn(null, stringifyOnce(clu, undefined, 0));
|
||||
});
|
||||
},
|
||||
list : function(opts, fn) {
|
||||
God.getMonitorData(fn);
|
||||
},
|
||||
stop : function(opts, fn) {
|
||||
God.stopAll(fn);
|
||||
}
|
||||
});
|
||||
};
|
||||
// Only require here because God init himself
|
||||
var God = require('./god.js');
|
||||
|
||||
Satan.onReady = function() {
|
||||
(function init() {
|
||||
if (process.env.DAEMON) {
|
||||
Satan.remoteWrapper();
|
||||
}
|
||||
else {
|
||||
isDaemonReachable(function(ab) {
|
||||
if (ab == false)
|
||||
return Satan.launchDaemon(Satan.launchRPC);
|
||||
return Satan.launchRPC();
|
||||
});
|
||||
}
|
||||
})();
|
||||
// Send ready message to Satan Client
|
||||
process.send({
|
||||
online : true, success : true, pid : process.pid
|
||||
});
|
||||
|
||||
var server = new rpc.Server(rep);
|
||||
|
||||
rep.bind(SATAN_PORT);
|
||||
|
||||
server.expose({
|
||||
prepare : function(opts, fn) {
|
||||
God.prepare(opts, function(err, clu) {
|
||||
fn(null, stringifyOnce(clu, undefined, 0));
|
||||
});
|
||||
},
|
||||
list : function(opts, fn) {
|
||||
God.getMonitorData(fn);
|
||||
},
|
||||
startId : function(opts, fn) {
|
||||
God.startProcessId(opts.id, function(err, clu) {
|
||||
fn(err, stringifyOnce(clu, undefined, 0));
|
||||
});
|
||||
},
|
||||
stop : function(opts, fn) {
|
||||
God.stopAll(fn);
|
||||
},
|
||||
killMe : function(fn) {
|
||||
console.log('Killing daemon');
|
||||
fn(null, {});
|
||||
process.exit(0);
|
||||
},
|
||||
findByScript : function(opts, fn) {
|
||||
fn(null, God.findByScript(opts.script));
|
||||
},
|
||||
daemonData: function(fn) {
|
||||
fn(null, {
|
||||
pid : process.pid
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Satan.launchRPC = function() {
|
||||
debug('Launching RPC client');
|
||||
Satan.client = new rpc.Client(req);
|
||||
this.ev = req.connect(66666);
|
||||
this.ev.on('connect', function() {
|
||||
process.emit('satan:ready');
|
||||
});
|
||||
debug('Launching RPC client');
|
||||
Satan.client = new rpc.Client(req);
|
||||
Satan.ev = req.connect(SATAN_PORT);
|
||||
Satan.ev.on('connect', function() {
|
||||
process.emit('satan:client:ready');
|
||||
});
|
||||
};
|
||||
|
||||
Satan.getExposedMethods = function(cb) {
|
||||
Satan.client.methods(function(err, methods) {
|
||||
cb(err, methods);
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Interface to connect to the client
|
||||
//
|
||||
Satan.executeRemote = function(method, opts, fn) {
|
||||
Satan.client.call(method, opts, function(err, res) {
|
||||
fn(err, res);
|
||||
});
|
||||
Satan.client.call(method, opts, function(err, res) {
|
||||
fn(err, res);
|
||||
});
|
||||
};
|
||||
|
||||
Satan.killDaemon = function(fn) {
|
||||
Satan.client.call('killMe', function(err, res) {
|
||||
fn(err, res);
|
||||
});
|
||||
};
|
||||
|
||||
Satan.launchDaemon = function(cb) {
|
||||
debug('Launching daemon');
|
||||
|
||||
var path = require('path');
|
||||
|
||||
var child = require("child_process").fork(path.resolve("./satan.js"), [], {
|
||||
silent : false,
|
||||
detached: true,
|
||||
cwd: process.cwd(),
|
||||
env : {
|
||||
"DAEMON" : true
|
||||
},
|
||||
stdio: "ignore"
|
||||
}, function(err, stdout, stderr) {
|
||||
debug(arguments);
|
||||
//console.log(stdout);
|
||||
});
|
||||
|
||||
child.unref();
|
||||
|
||||
child.once('message', function(msg) {
|
||||
console.log(msg);
|
||||
return cb(child);
|
||||
});
|
||||
debug('Launching daemon');
|
||||
|
||||
var path = require('path');
|
||||
|
||||
// Todo : Redirect daemon logs
|
||||
var child = require("child_process").fork(path.resolve("./satan.js"), [], {
|
||||
silent : false,
|
||||
detached: true,
|
||||
cwd: process.cwd(),
|
||||
env : {
|
||||
"DAEMON" : true
|
||||
},
|
||||
stdio: "ignore"
|
||||
}, function(err, stdout, stderr) {
|
||||
debug(arguments);
|
||||
});
|
||||
|
||||
child.unref();
|
||||
|
||||
child.once('message', function(msg) {
|
||||
process.emit('satan:daemon:ready');
|
||||
console.log(msg);
|
||||
return setTimeout(function() {cb(child)}, 100); // Put a little time out
|
||||
});
|
||||
};
|
||||
|
||||
// TODO : do it better
|
||||
Satan.pingDaemon = function(cb) {
|
||||
var req = axon.socket('req');
|
||||
var client = new rpc.Client(req);
|
||||
|
||||
debug('Trying to connect to server');
|
||||
client.sock.once('reconnect attempt', function() {
|
||||
client.sock.close();
|
||||
debug('Daemon not launched');
|
||||
cb(false);
|
||||
});
|
||||
client.sock.once('connect', function() {
|
||||
client.sock.close();
|
||||
debug('Daemon alive');
|
||||
cb(true);
|
||||
});
|
||||
req.connect(SATAN_PORT);
|
||||
};
|
||||
|
||||
// Change Circular dependies to null
|
||||
function stringifyOnce(obj, replacer, indent){
|
||||
var printedObjects = [];
|
||||
var printedObjectKeys = [];
|
||||
var printedObjects = [];
|
||||
var printedObjectKeys = [];
|
||||
|
||||
function printOnceReplacer(key, value){
|
||||
var printedObjIndex = false;
|
||||
printedObjects.forEach(function(obj, index){
|
||||
if(obj===value){
|
||||
printedObjIndex = index;
|
||||
}
|
||||
});
|
||||
function printOnceReplacer(key, value){
|
||||
var printedObjIndex = false;
|
||||
printedObjects.forEach(function(obj, index){
|
||||
if(obj===value){
|
||||
printedObjIndex = index;
|
||||
}
|
||||
});
|
||||
|
||||
if(printedObjIndex && typeof(value)=="object"){
|
||||
return "null";
|
||||
}else{
|
||||
var qualifiedKey = key || "(empty key)";
|
||||
printedObjects.push(value);
|
||||
printedObjectKeys.push(qualifiedKey);
|
||||
if(replacer){
|
||||
return replacer(key, value);
|
||||
}else{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if(printedObjIndex && typeof(value)=="object"){
|
||||
return "null";
|
||||
}else{
|
||||
var qualifiedKey = key || "(empty key)";
|
||||
printedObjects.push(value);
|
||||
printedObjectKeys.push(qualifiedKey);
|
||||
if(replacer){
|
||||
return replacer(key, value);
|
||||
}else{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(obj, printOnceReplacer, indent);
|
||||
}
|
||||
|
||||
// TODO : do it better
|
||||
function isDaemonReachable(cb) {
|
||||
var req = axon.socket('req');
|
||||
var client = new rpc.Client(req);
|
||||
|
||||
debug('Trying to connect to server');
|
||||
client.sock.once('reconnect attempt', function() {
|
||||
client.sock.close();
|
||||
debug('Daemon not launched');
|
||||
cb(false);
|
||||
});
|
||||
client.sock.once('connect', function() {
|
||||
client.sock.close();
|
||||
debug('Daemon alive');
|
||||
cb(true);
|
||||
});
|
||||
req.connect(66666);
|
||||
}
|
||||
return JSON.stringify(obj, printOnceReplacer, indent);
|
||||
}
|
||||
|
||||
Satan.onReady();
|
||||
|
||||
5
test/fixtures/child.js
vendored
5
test/fixtures/child.js
vendored
@ -10,8 +10,9 @@ console.log(process.env.NODE_UNIQUE_ID, cluster.isWorker);
|
||||
var i = 0;
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
res.writeHead(200);
|
||||
res.end("hello world\n" + i++);
|
||||
res.writeHead(200);
|
||||
console.log('rcv', process.pid);
|
||||
res.end("hello world\n" + i++);
|
||||
}).listen(8000);
|
||||
|
||||
// setTimeout(function() {
|
||||
|
||||
7
test/fixtures/echo.js
vendored
7
test/fixtures/echo.js
vendored
@ -1,9 +1,8 @@
|
||||
|
||||
setInterval(function() {
|
||||
console.log('ok');
|
||||
console.error('merde');
|
||||
}, 500);
|
||||
|
||||
setTimeout(function() {
|
||||
throw new Error('eh merde');
|
||||
}, 3000);
|
||||
// setTimeout(function() {
|
||||
// throw new Error('eh merde');
|
||||
// }, 3000);
|
||||
|
||||
@ -1,73 +1,76 @@
|
||||
|
||||
|
||||
var God = require('..');
|
||||
var numCPUs = require('os').cpus().length;
|
||||
|
||||
describe('God', function() {
|
||||
it('should have right properties', function() {
|
||||
God.should.have.property('prepare');
|
||||
God.should.have.property('getProcesses');
|
||||
God.should.have.property('getMonitorData');
|
||||
God.should.have.property('getFormatedProcesses');
|
||||
God.should.have.property('checkProcess');
|
||||
God.should.have.property('stopAll');
|
||||
it('should have right properties', function() {
|
||||
God.should.have.property('prepare');
|
||||
God.should.have.property('getProcesses');
|
||||
God.should.have.property('getMonitorData');
|
||||
God.should.have.property('getFormatedProcesses');
|
||||
God.should.have.property('checkProcess');
|
||||
God.should.have.property('stopAll');
|
||||
God.should.have.property('stopProcessId');
|
||||
});
|
||||
|
||||
describe('One process', function() {
|
||||
var proc;
|
||||
|
||||
after(function(done) {
|
||||
God.stopAll(done);
|
||||
});
|
||||
|
||||
describe('One process', function() {
|
||||
var proc;
|
||||
|
||||
after(function(done) {
|
||||
God.stopAll(done);
|
||||
});
|
||||
|
||||
it('should fork one process', function(done) {
|
||||
God.prepare({
|
||||
script : './test/fixtures/echo.js',
|
||||
fileError : 'logs/echoErr.log',
|
||||
fileOutput : 'logs/echoLog.log',
|
||||
pidFile : 'pids/child'
|
||||
}, function(err, proce) {
|
||||
proc = proce;
|
||||
proc.status.should.be.equal('online');
|
||||
God.getFormatedProcesses().length.should.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should stop process and no more present', function(done) {
|
||||
proc.status.should.be.equal('online');
|
||||
God.checkProcess(proc.process.pid).should.be.true;
|
||||
proc.stop(function() {
|
||||
God.getFormatedProcesses().length.should.equal(1);
|
||||
God.checkProcess(proc.process.pid).should.be.false;
|
||||
proc.status.should.be.equal('stopped');
|
||||
done()
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should start the process', function(done) {
|
||||
proc.start(function(err, proc) {
|
||||
God.checkProcess(proc.process.pid).should.be.true;
|
||||
proc.status.should.be.equal('online');
|
||||
console.log(God.getFormatedProcesses());
|
||||
God.getFormatedProcesses().length.should.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should fork one process', function(done) {
|
||||
God.prepare({
|
||||
script : './test/fixtures/echo.js',
|
||||
fileError : 'logs/echoErr.log',
|
||||
fileOutput : 'logs/echoLog.log',
|
||||
pidFile : 'pids/child'
|
||||
}, function(err, proce) {
|
||||
proc = proce;
|
||||
proc.status.should.be.equal('online');
|
||||
God.getFormatedProcesses().length.should.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multi launching', function() {
|
||||
it('should launch multiple processes', function(done) {
|
||||
God.prepare({
|
||||
script : './test/fixtures/child.js',
|
||||
fileError : 'logs/errLog.log',
|
||||
fileOutput : 'logs/outLog.log',
|
||||
pidFile : 'pids/child',
|
||||
instances : 'max'
|
||||
}, function(err, procs) {
|
||||
God.getFormatedProcesses().length.should.equal(5);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
it('should stop process and no more present', function(done) {
|
||||
proc.status.should.be.equal('online');
|
||||
God.checkProcess(proc.process.pid).should.be.true;
|
||||
God.stopProcess(proc, function() {
|
||||
God.getFormatedProcesses().length.should.equal(0);
|
||||
God.checkProcess(proc.process.pid).should.be.false;
|
||||
proc.status.should.be.equal('stopped');
|
||||
done()
|
||||
});
|
||||
});
|
||||
|
||||
// Process stopped are not anymore cached in db
|
||||
it.skip('should start the process', function(done) {
|
||||
God.startProcess(proc, function(err, proc) {
|
||||
God.checkProcess(proc.process.pid).should.be.true;
|
||||
proc.status.should.be.equal('online');
|
||||
God.getFormatedProcesses().length.should.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multi launching', function() {
|
||||
it('should launch multiple processes depending on CPUs available', function(done) {
|
||||
God.prepare({
|
||||
script : './test/fixtures/child.js',
|
||||
fileError : 'logs/errLog.log',
|
||||
fileOutput : 'logs/outLog.log',
|
||||
pidFile : 'pids/child',
|
||||
instances : 'max'
|
||||
}, function(err, procs) {
|
||||
God.getFormatedProcesses().length.should.equal(numCPUs);
|
||||
procs.length.should.equal(numCPUs);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
11
test/monit.mocha.js
Normal file
11
test/monit.mocha.js
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
var Monit = require('../lib/monit.js');
|
||||
var should = require('should');
|
||||
var assert = require('better-assert');
|
||||
|
||||
describe('Monit', function() {
|
||||
it('should have right properties', function() {
|
||||
Monit.should.have.property('init');
|
||||
Monit.should.have.property('refresh');
|
||||
});
|
||||
});
|
||||
88
test/satan.mocha.js
Normal file
88
test/satan.mocha.js
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
var Satan;
|
||||
var should = require('should');
|
||||
var assert = require('better-assert');
|
||||
|
||||
describe('Satan', function() {
|
||||
|
||||
after(function(done) {
|
||||
Satan.killDaemon(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should auto instancy itself, fire event and kill daemon', function(done) {
|
||||
Satan = require('../satan.js');
|
||||
process.once('satan:client:ready', function() {
|
||||
console.log('Client ready');
|
||||
Satan.killDaemon(function() {
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('should start daemon', function(done) {
|
||||
Satan.launchDaemon(function(child) {
|
||||
assert(typeof child.pid == 'number');
|
||||
Satan.pingDaemon(function(online) {
|
||||
console.log(online);
|
||||
assert(online == true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have right properties', function() {
|
||||
Satan.should.have.property('remoteWrapper');
|
||||
Satan.should.have.property('onReady');
|
||||
Satan.should.have.property('launchRPC');
|
||||
Satan.should.have.property('executeRemote');
|
||||
Satan.should.have.property('launchDaemon');
|
||||
Satan.should.have.property('getExposedMethods');
|
||||
Satan.should.have.property('pingDaemon');
|
||||
Satan.should.have.property('killDaemon');
|
||||
});
|
||||
|
||||
|
||||
describe('DAEMON', function() {
|
||||
it('should have the right exposed methods via RPC', function(done) {
|
||||
Satan.getExposedMethods(function(err, methods) {
|
||||
assert(err == null);
|
||||
methods.should.have.property('prepare');
|
||||
methods.should.have.property('list');
|
||||
methods.should.have.property('stop');
|
||||
methods.should.have.property('killMe');
|
||||
methods.should.have.property('daemonData');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get an empty process list', function(done) {
|
||||
Satan.executeRemote('list', {}, function(err, res) {
|
||||
assert(res.length === 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should launch a process', function(done) {
|
||||
Satan.executeRemote('prepare', {
|
||||
script : './test/fixtures/child.js',
|
||||
fileError : 'logs/errLog.log',
|
||||
fileOutput : 'logs/outLog.log',
|
||||
pidFile : 'pids/child',
|
||||
instances : 'max'
|
||||
}, function(err, procs) {
|
||||
assert(err == null);
|
||||
assert(JSON.parse(procs).length == 4);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should list 4 processes', function(done) {
|
||||
Satan.executeRemote('list', {}, function(err, res) {
|
||||
assert(res.length === 4);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user