mhl-dispatcher
Version:
A node dispatcher server for running and managing batch processes
374 lines (352 loc) • 12.1 kB
JavaScript
var os = require('os'),
db = require('./db.js'),
proc = require('./proc.js'),
error = require('./error.js'),
logger = require('./logger.js'),
clc = require('cli-color'),
util = require('util'),
server = {};
;
logger.server = server;
//-------------------------------Server Utils----------------------------------------
server.utils = {
factory: function(fnName, callback, args){
return function(){
var args = Array.prototype.slice.call(arguments);
server.current.funcName = fnName;
server.current.funcState = 'started';
if(!logger.silent){
logger.serverLog(server.current.funcName + ' is running.', server.CONSTANTS.Types.INFO);
}
callback.apply(this, args);
};
}
};
//--------------Server Settings ------------------------------------------------------
server.hostname = os.hostname();
server.serverId = 0;
server.sleep = 1000;
server.current = {
funcName: '',
funcState: '',
timeout: null,
batch: 0,
childProcess: null,
childProcessCommand: null
};
server.CONSTANTS = {
Severity: {
SUMMARY: 8,
DEBUG: 7,
INFO: 6,
NOTICE: 5,
WARNING: 4,
ERROR: 3,
CRITICAL: 2,
ALERT: 1,
EMERGENCY: 0
},
Types: {
SUMMARY: 'summary',
DEBUG: 'debug',
INFO: 'info',
NOTICE: 'notice',
WARNING: 'warning',
ERROR: 'error',
CRITICAL: 'critical',
ALERT: 'alert',
EMERGENCY: 'emergency'
}
};
//-----------------Server Constants----------------------------------------------------
server.batch = {
STATUS: {
INPROCESS: 'inprocess',
DONE: 'done',
ERROR: 'error',
KILLED: 'killed'
}
};
//-------------------Server Status Definitions-------------------------------------------
server.status = {
starting: {
name:'starting',
task: server.utils.factory('server.status.starting.task', function(){
server.current.funcState = 'server going into waiting state...';
server.runTask(server.status.waiting);
})
},
preparing: {
name: 'preparing',
task: server.utils.factory('server.status.preparing.task', function(){
server.prepareProcess(function(processReady){
if(processReady){
server.runTask(server.status.processing);
}else{
server.runTask(server.status.waiting);
}
});
})
},
waiting: {
name: 'waiting',
task: server.utils.factory('server.status.waiting.task', function(){
server.getBatch(function(batchReady){
if(batchReady){
server.runTask(server.status.preparing);
}else{
server.runTask (server.status.waiting, server.sleep);
}
});
})
},
processing: {
name: 'processing',
task: server.utils.factory('server.status.processing.task', function(){
server.runProcess(function(success){
server.runTask(server.status.waiting);
});
logger.silent = true;
server.runTask(server.status.processing, server.sleep);
})
},
stopping: {
name:'stopping',
task: server.utils.factory('server.status.stopping.task', function(){
server.killProcess(function(killed){
if(killed){
server.runTask(server.status.waiting, server.sleep);
}else{
server.runTask(server.status.stopping, server.sleep);
}
});
})
},
exited: {
name: 'exited',
task: server.utils.factory('server.status.exited.task', function(){
server.quit();
})
}
};
//-----------------Server Methods ----------------------------------
server.runTask = server.utils.factory('server.runTask', function(status, delay){
delay = delay || 0;
var type = server.CONSTANTS.Types,
severity = server.CONSTANTS.Severity;
if(server.current.timeout){
clearTimeout(server.current.timeout);
}
server.current.timeout = setTimeout(function(){
db.setServerStatus(server.serverId, status.name, function(err, rowsAffected, params){
var statusCode;
if(err){
server.current.funcState = 'db.setServerStatus: Error running task';
logger.serverLog('Cannot find Oracle DB Server...', type.ERROR);
server.reconnect();
}else {
//run the task
statusCode = params.pBSSTATUSCODE;
try{
server.status[statusCode].task();
}catch(e){
server.current.funcState = 'db.setServerStatus: Error running task';
logger.fullLog(severity.ERROR, 'Invalid status ['+ statusCode +'] - '+ e, type.ERROR);
server.runTask(server.status.waiting, server.sleep);
}
}
});
}, delay);
});
server.register = server.utils.factory('server.register', function(){
var serverTypes = server.CONSTANTS.Types;
db.registerServer(server.hostname, function(err, rowsAffected, params){
if(err){
server.current.funcState = 'db.registerServer: Error registering server';
logger.serverLog('Could not register server', serverTypes.ERROR);
server.cleanup();
server.reconnect();
}else{
if(params && params.SERVERID !== 1){
server.serverId = params.SERVERID;
server.current.funcState = 'db.registerServer: Server Registered';
logger.serverLog(server.hostname +' has been registered with server id: '+ server.serverId , serverTypes.INFO);
//start up the server
server.runTasks();
}
}
});
});
server.runTasks = server.utils.factory('server.runTasks', function(){
logger.group = 'Processing Batches';
server.runTask(server.status.waiting, server.sleep);
});
server.boot = server.utils.factory('server.boot', function(){
var cn = '',
type = server.CONSTANTS.Types;
cn = db.connect();
if(cn === ''){
server.current.funcState = 'db.connect: Server connected';
logger.serverLog('Server connected to oracle', type.INFO);
server.register();
}else{
server.current.funcState = 'db.connect: Server could not connect';
logger.serverLog(cn, type.ERROR);
server.reconnect(server.sleep);
}
});
server.reconnect = server.utils.factory('server.reconnect', function(delay){
delay = delay || 0;
var o = '',
type = server.CONSTANTS.Types;
setTimeout(function(){
o = db.reconnect();
if(o === ''){
server.current.funcState = 'db.reconnect: Server Reconnected';
logger.serverLog('Server reconnected to oracle', type.INFO);
server.register();
}else{
server.current.funcState = 'db.reconnect: Error reconnecting..';
logger.serverLog(o, type.ERROR);
server.reconnect(server.sleep);
}
}, delay);
});
server.runProcess = server.utils.factory('server.runProcess', function(callback){
var serverTypes = server.CONSTANTS.Types,
severity = server.CONSTANTS.Severity,
batchStatus = server.batch.STATUS;
if(server.currentChildProcessCommand !== null){
server.currentChildProcess = proc.run(server.currentChildProcessCommand, function(err, stdout, stderr){
var errMessage,
cbStatus,
cbState,
cbMessage,
cbSev,
cbType,
success = false;
logger.silent = false;
if(err == null && !stderr){
server.current.funcState = 'Child process complete';
logger.fullLog(severity.INFO, stdout, serverTypes.INFO);
//set the server done status
cbStatus = batchStatus.DONE;
cbState = 'db.setBatchStatus: Batch done';
cbMessage = 'Batch #' + server.current.batch + ' done.';
cbSev = severity.INFO;
cbType = serverTypes.INFO;
success = true;
}else{
server.current.funcState = 'Error processing batch or batch has been killed.';
errMessage = err != null && !stderr ? 'Err [ ' + err + ' ] ' : ' Stderr [ ' + stderr + ' ] ';
logger.fullLog(severity.ERROR, errMessage, serverTypes.ERROR);
cbStatus = batchStatus.ERROR;
cbState = 'db.setBatchStatus: Batch Error';
cbMessage = 'Error processing Batch #' + server.current.batch;
cbSev = severity.ERROR;
cbType = serverTypes.ERROR;
success = false;
}
//set the batch status
db.setBatchStatus(server.current.batch, cbStatus, function(){
server.current.funcState = cbState;
logger.fullLog(cbSev, cbMessage, cbType);
//set the status of the server
db.setServerBatchDone(server.serverId, server.current.batch, function(){
server.current.funcState = 'db.setServerBatchDone: Batch Done';
logger.fullLog(severity.INFO, 'Batch Done', serverTypes.INFO);
callback(success);
});
});
});
//reset command after it has been launched
server.currentChildProcessCommand = null;
}
});
server.prepareProcess = server.utils.factory('server.prepareProcess', function(callback){
var serverTypes = server.CONSTANTS.Types,
severity = server.CONSTANTS.Severity,
ready = false;
//get the batch parameters
if(!server.current.batch || server.current.batch === 0){
server.current.funcState = 'Invalid Batch';
ready = false;
logger.serverLog('Invalid Batch or no batch has been set', serverTypes.ERROR);
}
db.getBatchParameters(server.current.batch, function(err, rowsAffected, parameters){
var exePath, args, cmd;
if(err){
server.current.funcState = 'db.getBatchParameters: Error getting Batch parameters';
ready = false;
logger.fullLog(severity.ERROR, err, serverTypes.ERROR);
}else{
//get & prepare process parameters
exePath = proc.getExecutablePath(parameters.pResultJSON.batchparameters.ApplicationKey.PVALUE);
args = parameters.pResultJSON.batchparameters.CommandLineArgs.PVALUE;
server.currentChildProcessCommand = proc.stringify(exePath, args);
server.current.funcState = 'db.getBatchParameters: Batch parameters received, Command ready';
ready = true;
logger.fullLog(severity.INFO, 'Command to be processed:\n' + server.currentChildProcessCommand, serverTypes.INFO);
}
callback(ready);
});
});
server.killProcess = server.utils.factory('server.killProcess', function(callback){
var serverTypes = server.CONSTANTS.Types,
severity = server.CONSTANTS.Severity,
batchStatus = server.batch.STATUS;
if(server.currentChildProcess){
proc.kill(server.currentChildProcess.pid, function(err, stdout, stderr){
var killed = false;
if(err == null && !stderr && stdout){
server.current.funcState = 'Child process killed';
logger.fullLog(severity.INFO, stdout, serverTypes.WARNING);
server.currentChildProcess = null;
server.currentChildProcessCommand = null;
killed = true;
logger.fullLog(severity.INFO, 'Batch process #' + server.current.batch + ' killed.', serverTypes.WARNING);
}else{
server.current.funcState = 'Error killing process';
errMessage = err != null && !stderr ? 'err: ' + err : 'std-err: ' + stderr;
killed = false;
logger.fullLog(severity.ERROR, errMessage, serverTypes.ERROR);
}
callback(killed);
});
}
});
server.getBatch = server.utils.factory('server.getBatch', function(callback){
var serverTypes = server.CONSTANTS.Types,
severity = server.CONSTANTS.Severity,
ready = false;
//get the next batch
db.getNextBatch(server.serverId, function(err, rowsAffected, parameters){
if(err){
server.current.funcState = 'db.getNextBatch: Error getting batch';
logger.serverLog(err, serverTypes.ERROR);
}
if(parameters.pBATCHID === 'null'){
server.current.funcState = 'db.getNextBatch: Waiting for a new batch';
logger.silent = true;
ready = false;
} else {
//set the current batch and go into "processing" mode
logger.silent = false;
server.current.batch = parameters.pBATCHID;
server.current.funcState = 'db.getNextBatch: Batch Received';
ready = true;
logger.fullLog(severity.INFO, 'Server ' + server.serverId +' received batch #'+ server.current.batch + ' for processing.', serverTypes.INFO);
}
callback(ready);
});
});
server.cleanup = server.utils.factory('server.cleanup', function(){
//kill any current process running
server.killProcess();
});
server.quit = server.utils.factory('server.quit', function(){
server.cleanup();
db.dispose();
});
//---------------boot the server (entry point) ----------------------------------
server.boot();