UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

329 lines (302 loc) 10.6 kB
var Channel, Q, TaskModel, TransactionModel, activeTasks, config, finalizeTaskRound, findAndProcessAQueuedTask, http, live, logger, net, processNextTaskRound, rerunGetTransaction, rerunHttpRequestSend, rerunMiddleware, rerunSetHTTPRequestOptions, rerunTaskProcessor, rerunTcpRequestSend, rerunTransaction; TaskModel = require('./model/tasks').Task; Channel = require('./model/channels').Channel; Q = require("q"); logger = require("winston"); config = require("./config/config"); config.rerun = config.get('rerun'); http = require('http'); TransactionModel = require("./model/transactions").Transaction; net = require("net"); rerunMiddleware = require("./middleware/rerunUpdateTransactionTask"); live = false; activeTasks = 0; findAndProcessAQueuedTask = function() { return TaskModel.findOneAndUpdate({ status: 'Queued' }, { status: 'Processing' }, { 'new': true }, function(err, task) { if (err) { return logger.error("An error occurred while looking for rerun tasks: " + err); } else if (task) { activeTasks++; processNextTaskRound(task, function(err) { if (err) { logger.error("An error occurred while processing rerun task " + task._id + ": " + err); } activeTasks--; if (live) { return findAndProcessAQueuedTask(); } }); if (live) { return findAndProcessAQueuedTask(); } } }); }; rerunTaskProcessor = function() { if (live) { findAndProcessAQueuedTask(); return setTimeout(rerunTaskProcessor, config.rerun.processor.pollPeriodMillis); } }; exports.start = function(callback) { live = true; setTimeout(rerunTaskProcessor, config.rerun.processor.pollPeriodMillis); logger.info("Started rerun task processor"); return callback(); }; exports.stop = function(callback) { var waitForActiveTasks; live = false; waitForActiveTasks = function() { if (activeTasks > 0) { return setTimeout(waitForActiveTasks, 100); } else { logger.info("Stopped rerun task processor"); return callback(); } }; return waitForActiveTasks(); }; exports.isRunning = function() { return live; }; finalizeTaskRound = function(task, callback) { return TaskModel.findOne({ _id: task._id }, { status: 1 }, function(err, result) { if (err) { return callback(err); } if (result.status === 'Processing' && task.remainingTransactions !== 0) { task.status = 'Queued'; logger.info("Round completed for rerun task #" + task._id + " - " + task.remainingTransactions + " transactions remaining"); } else { if (task.remainingTransactions === 0) { task.status = 'Completed'; task.completedDate = new Date(); logger.info("Round completed for rerun task #" + task._id + " - Task completed"); } else { task.status = result.status; logger.info("Round completed for rerun task #" + task._id + " - Task has been " + result.status); } } return task.save(function(err) { return callback(err); }); }); }; processNextTaskRound = function(task, callback) { var fn, i, len, nextI, promises, ref, transaction; logger.debug("Processing next task round: total transactions = " + task.totalTransactions + ", remainingTransactions = " + task.remainingTransactions); promises = []; nextI = task.transactions.length - task.remainingTransactions; ref = task.transactions.slice(nextI, nextI + task.batchSize); fn = function(transaction) { var defer; defer = Q.defer(); rerunTransaction(transaction.tid, task._id, function(err, response) { if (err) { transaction.tstatus = 'Failed'; transaction.error = err; logger.error("An error occurred while rerunning transaction " + transaction.tid + " for task " + task._id + ": " + err); } else if ((response != null ? response.status : void 0) === 'Failed') { transaction.tstatus = 'Failed'; transaction.error = response.message; logger.error("An error occurred while rerunning transaction " + transaction.tid + " for task " + task._id + ": " + err); } else { transaction.tstatus = 'Completed'; } task.remainingTransactions--; return defer.resolve(); }); transaction.tstatus = 'Processing'; return promises.push(defer.promise); }; for (i = 0, len = ref.length; i < len; i++) { transaction = ref[i]; fn(transaction); } return (Q.all(promises)).then(function() { return task.save(function(err) { if (err != null) { logger.error("Failed to save current task while processing round: taskID=" + task._id + ", err=" + err, err); } return finalizeTaskRound(task, callback); }); }); }; rerunTransaction = function(transactionID, taskID, callback) { return rerunGetTransaction(transactionID, function(err, transaction) { if (err) { return callback(err); } return Channel.findById(transaction.channelID, function(err, channel) { if (err) { return callback(err); } logger.info("Rerunning " + channel.type + " transaction"); if (channel.type === 'http' || channel.type === 'polling') { rerunSetHTTPRequestOptions(transaction, taskID, function(err, options) { if (err) { return callback(err); } return rerunHttpRequestSend(options, transaction, function(err, HTTPResponse) { return callback(err, HTTPResponse); }); }); } if (channel.type === 'tcp' || channel.type === 'tls') { return rerunTcpRequestSend(channel, transaction, function(err, TCPResponse) { var ctx; if (err) { return callback(err); } ctx = { parentID: transaction._id, transactionId: transactionID, transactionStatus: TCPResponse.status, taskID: taskID }; return rerunMiddleware.updateOriginalTransaction(ctx, function(err) { if (err) { return callback(err); } return rerunMiddleware.updateTask(ctx, callback); }); }); } }); }); }; rerunGetTransaction = function(transactionID, callback) { return TransactionModel.findById(transactionID, function(err, transaction) { if (transaction == null) { return callback(new Error("Transaction " + transactionID + " could not be found"), null); } if (!transaction.canRerun) { err = new Error("Transaction " + transactionID + " cannot be rerun as there isn't enough information about the request"); return callback(err, null); } return callback(null, transaction); }); }; rerunSetHTTPRequestOptions = function(transaction, taskID, callback) { var err, options; if (transaction === null) { err = new Error("An empty Transaction object was supplied. Aborting HTTP options configuration"); return callback(err, null); } logger.info('Rerun Transaction #' + transaction._id + ' - HTTP Request options being configured'); options = { hostname: config.rerun.host, port: config.rerun.httpPort, path: transaction.request.path, method: transaction.request.method, headers: transaction.request.headers }; if (transaction.clientID) { options.headers.clientID = transaction.clientID; } options.headers.parentID = transaction._id; options.headers.taskID = taskID; if (transaction.request.querystring) { options.path += "?" + transaction.request.querystring; } return callback(null, options); }; rerunHttpRequestSend = function(options, transaction, callback) { var err, req, response; if (options === null) { err = new Error("An empty 'Options' object was supplied. Aborting HTTP Send Request"); return callback(err, null); } if (transaction === null) { err = new Error("An empty 'Transaction' object was supplied. Aborting HTTP Send Request"); return callback(err, null); } response = { body: '', transaction: {} }; logger.info('Rerun Transaction #' + transaction._id + ' - HTTP Request is being sent...'); req = http.request(options, function(res) { res.on("data", function(chunk) { return response.body += chunk; }); return res.on("end", function(err) { if (err) { response.transaction.status = "Failed"; } else { response.transaction.status = "Completed"; } response.status = res.statusCode; response.message = res.statusMessage; response.headers = res.headers; response.timestamp = new Date; logger.info('Rerun Transaction #' + transaction._id + ' - HTTP Response has been captured'); return callback(null, response); }); }); req.on("error", function(err) { if (err) { response.transaction.status = "Failed"; } response.status = 500; response.message = "Internal Server Error"; response.timestamp = new Date; return callback(null, response); }); if (transaction.request.method === "POST" || transaction.request.method === "PUT") { req.write(transaction.request.body); } return req.end(); }; rerunTcpRequestSend = function(channel, transaction, callback) { var client, response; response = { body: '', transaction: {} }; client = new net.Socket(); client.connect(channel.tcpPort, channel.tcpHost, function() { logger.info("Rerun Transaction " + transaction._id + ": TCP connection established"); client.end(transaction.request.body); }); client.on("data", function(data) { return response.body += data; }); client.on("end", function(data) { response.status = 200; response.transaction.status = "Completed"; response.message = ''; response.headers = {}; response.timestamp = new Date; logger.info('Rerun Transaction #' + transaction._id + ' - TCP Response has been captured'); callback(null, response); }); return client.on("error", function(err) { if (err) { response.transaction.status = "Failed"; } response.status = 500; response.message = "Internal Server Error"; response.timestamp = new Date; return callback(err, response); }); }; if (process.env.NODE_ENV === "test") { exports.rerunGetTransaction = rerunGetTransaction; exports.rerunSetHTTPRequestOptions = rerunSetHTTPRequestOptions; exports.rerunHttpRequestSend = rerunHttpRequestSend; exports.rerunTcpRequestSend = rerunTcpRequestSend; exports.findAndProcessAQueuedTask = findAndProcessAQueuedTask; } //# sourceMappingURL=tasks.js.map