UNPKG

pipeproc

Version:

Multi-process log processing for nodejs

525 lines (524 loc) 20.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const debug_1 = __importDefault(require("debug")); const path_1 = require("path"); const leveldown_1 = __importDefault(require("leveldown")); const memdown_1 = __importDefault(require("memdown")); const messages_1 = require("../common/messages"); const commitLog_1 = require("./commitLog"); const restoreState_1 = require("./restoreState"); const shutdown_1 = require("./shutdown"); const getRange_1 = require("./getRange"); const proc_1 = require("./proc"); const systemProc_1 = require("./systemProc"); const workerManager_1 = require("./workerManager"); const ack_1 = require("./ack"); const ackCommitLog_1 = require("./ackCommitLog"); const destroyProc_1 = require("./destroyProc"); const messaging_1 = require("./messaging"); const writeBuffer_1 = require("./writeBuffer"); const resumeDisableProc_1 = require("./resumeDisableProc"); const reclaimProc_1 = require("./reclaimProc"); const collect_1 = require("./gc/collect"); const waitForProcs_1 = require("./waitForProcs"); const tones_1 = require("./tones"); const d = debug_1.default("pipeproc:node"); let db; let connectionAddress; let serverSocket; let clientTLS; const activeTopics = {}; const systemState = { active: false }; const messageRegistry = {}; const writeBuffer = []; let stopWriteBuffer; const activeProcs = []; const activeSystemProcs = []; const activeWorkers = []; let gcInterval; messaging_1.registerMessage(messageRegistry, { messageType: "system_init", replySuccess: "system_ready", replyError: "system_ready_error", writeOp: true, listener: function (data, callback) { if (systemState.active) { return callback("system_already_active"); } d("starting up..."); if (data.options.memory) { d("using in-memory adapter"); db = memdown_1.default(); } else { d("using disk adapter"); if (data.options.location) { let location; if (path_1.isAbsolute(data.options.location)) { location = data.options.location; } else { location = path_1.resolve(data.options.location); } d("data location:", location); db = leveldown_1.default(location); } else { db = leveldown_1.default("./pipeproc"); } } restoreState_1.restoreState(db, activeTopics, systemState, activeProcs, activeSystemProcs, data.options.memory, function (err) { if (err) { callback((err && err.message) || "uknown_error"); } else { workerManager_1.spawnWorkers(data.options.workers, activeWorkers, activeProcs, activeSystemProcs, connectionAddress, clientTLS, data.options.workerConcurrency, data.options.workerRestartAfter, function (spawnErr) { if (err) { callback((spawnErr && spawnErr.message) || "uknown_error"); } else { if (data.options.gc) { d("gc is enabled"); const MIN_PRUNE_TIME = (data.options.gc && data.options.gc.minPruneTime) || 30000; const GC_INTERVAL = (data.options.gc && data.options.gc.interval) || 30000; let gcRunning = false; gcInterval = setInterval(function () { if (gcRunning) return; d("gc will start running..."); gcRunning = true; collect_1.collect(db, activeTopics, activeProcs, { minPruneTime: MIN_PRUNE_TIME }, function (gcErr) { if (gcErr) { d("gc error:", gcErr); } gcRunning = false; d("gc ended"); }); }, GC_INTERVAL); } else { d("gc is disabled"); } callback(); } }); } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "ping", replySuccess: "pong", replyError: "ping_error", writeOp: false, listener: function (_data, callback) { callback(); } }); messaging_1.registerMessage(messageRegistry, { messageType: "wait_for_procs", replySuccess: "procs_completed", replyError: "procs_completed_error", writeOp: false, listener: function (data, callback) { d("waiting for procs..."); waitForProcs_1.waitForProcs(activeTopics, activeProcs, data.procs, function () { callback(); }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "commit", replySuccess: "commit_completed", replyError: "commit_error", writeOp: true, listener: function (data, callback) { commitLog_1.commitLog(db, activeTopics, data.commitLog, function (err, id) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (id && Array.isArray(id)) { callback(null, { id: id.map(tones_1.convertToClientId) }); } else if (id) { callback(null, { id: tones_1.convertToClientId(id) }); } else { callback("uncommited"); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "get_range", replySuccess: "range_reply", replyError: "range_error", writeOp: false, listener: function (data, callback) { getRange_1.getRange(db, activeTopics, data.topic, tones_1.convertRangeParams(data.options.start), tones_1.convertRangeParams(data.options.end), data.options.limit, data.options.exclusive, data.options.reverse, function (err, results) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (results) { callback(null, { results: results.map(function (re) { return { id: tones_1.convertToClientId(re.id), data: re.data }; }) }); } else { callback(); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "proc", replySuccess: "proc_ok", replyError: "proc_error", writeOp: true, listener: function (data, callback) { proc_1.proc(db, activeProcs, activeTopics, data.options, function (err, log) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (log) { if (Array.isArray(log)) { callback(null, log.map(function (l) { return { id: tones_1.convertToClientId(l.id), data: l.data }; })); } else { callback(null, { id: tones_1.convertToClientId(log.id), data: log.data }); } } else { callback(); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "available_proc", replySuccess: "available_proc_ok", replyError: "available_proc_error", writeOp: true, listener: function (data, callback) { proc_1.getAvailableProc(db, activeProcs, activeTopics, data.procList, function (err, result) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (result) { let log; if (result.log) { if (Array.isArray(result.log)) { log = result.log.map(function (l) { return { id: tones_1.convertToClientId(l.id), data: l.data }; }); } else { log = { id: tones_1.convertToClientId(result.log.id), data: result.log.data }; } } callback(null, { procName: result.procName, log: log }); } else { callback(); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "system_proc", replySuccess: "system_proc_ok", replyError: "system_proc_error", writeOp: true, listener: function (data, callback) { systemProc_1.systemProc(db, activeProcs, activeSystemProcs, activeWorkers, data.options, function (err, theProc) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (Array.isArray(theProc)) { callback(null, { proc: theProc.map(function (p) { const myProc = JSON.parse(JSON.stringify(p)); myProc.lastAckedRange = tones_1.convertToClientId(myProc.lastAckedRange); myProc.lastClaimedRange = tones_1.convertToClientId(myProc.lastClaimedRange); myProc.previousClaimedRange = tones_1.convertToClientId(myProc.previousClaimedRange); return myProc; }) }); } else if (theProc) { const myProc = JSON.parse(JSON.stringify(theProc)); myProc.lastAckedRange = tones_1.convertToClientId(myProc.lastAckedRange); myProc.lastClaimedRange = tones_1.convertToClientId(myProc.lastClaimedRange); myProc.previousClaimedRange = tones_1.convertToClientId(myProc.previousClaimedRange); callback(null, { proc: myProc }); } else { callback(); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "ack", replySuccess: "ack_ok", replyError: "ack_error", writeOp: true, listener: function (data, callback) { ack_1.ack(db, activeProcs, data.procName, function (err, ackedLogId) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (ackedLogId) { callback(null, { id: tones_1.convertToClientId(ackedLogId) }); } else { callback("invalid_ack"); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "ack_commit", replySuccess: "ack_commit_completed", replyError: "ack_commit_error", writeOp: true, listener: function (data, callback) { ackCommitLog_1.ackCommitLog(db, activeTopics, activeProcs, data.procName, data.commitLog, function (err, status) { if (err) { callback((err && err.message) || "uknown_error"); } else { let ackedLogId = status[0]; let commitedId = status[1]; if (status && ackedLogId && commitedId) { ackedLogId = tones_1.convertToClientId(ackedLogId); if (Array.isArray(commitedId)) { commitedId = commitedId.map(tones_1.convertToClientId); } else { commitedId = tones_1.convertToClientId(commitedId); } callback(null, { ackedLogId: ackedLogId, id: commitedId }); } else { callback("invalid_ack_or_commit"); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "inspect_proc", replySuccess: "inspect_proc_reply", replyError: "inspect_proc_error", writeOp: false, listener: function (data, callback) { const theProc = activeProcs.find(p => p.name === data.procName); d("proc inspection request:", data.procName); if (theProc) { const myProc = JSON.parse(JSON.stringify(theProc)); myProc.lastAckedRange = tones_1.convertToClientId(myProc.lastAckedRange); myProc.lastClaimedRange = tones_1.convertToClientId(myProc.lastClaimedRange); myProc.previousClaimedRange = tones_1.convertToClientId(myProc.previousClaimedRange); callback(null, { proc: myProc }); } else { callback("invalid_proc"); } } }); messaging_1.registerMessage(messageRegistry, { messageType: "destroy_proc", replySuccess: "destroy_proc_ok", replyError: "destroy_proc_error", writeOp: true, listener: function (data, callback) { destroyProc_1.destroyProc(db, activeProcs, data.procName, function (err, theProc) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (theProc) { const myProc = JSON.parse(JSON.stringify(theProc)); myProc.lastAckedRange = tones_1.convertToClientId(myProc.lastAckedRange); myProc.lastClaimedRange = tones_1.convertToClientId(myProc.lastClaimedRange); myProc.previousClaimedRange = tones_1.convertToClientId(myProc.previousClaimedRange); callback(null, { proc: myProc }); } else { callback("invalid_proc"); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "disable_proc", replySuccess: "disable_proc_ok", replyError: "disable_proc_error", writeOp: true, listener: function (data, callback) { resumeDisableProc_1.disableProc(db, activeProcs, data.procName, function (err, theProc) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (theProc) { const myProc = JSON.parse(JSON.stringify(theProc)); myProc.lastAckedRange = tones_1.convertToClientId(myProc.lastAckedRange); myProc.lastClaimedRange = tones_1.convertToClientId(myProc.lastClaimedRange); myProc.previousClaimedRange = tones_1.convertToClientId(myProc.previousClaimedRange); callback(null, { proc: myProc }); } else { callback("invalid_proc"); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "resume_proc", replySuccess: "resume_proc_ok", replyError: "resume_proc_error", writeOp: true, listener: function (data, callback) { resumeDisableProc_1.resumeProc(db, activeProcs, data.procName, function (err, theProc) { if (err) { callback((err && err.message) || "uknown_error"); } else { if (theProc) { const myProc = JSON.parse(JSON.stringify(theProc)); myProc.lastAckedRange = tones_1.convertToClientId(myProc.lastAckedRange); myProc.lastClaimedRange = tones_1.convertToClientId(myProc.lastClaimedRange); myProc.previousClaimedRange = tones_1.convertToClientId(myProc.previousClaimedRange); callback(null, { proc: myProc }); } else { callback("invalid_proc"); } } }); } }); messaging_1.registerMessage(messageRegistry, { messageType: "reclaim_proc", replySuccess: "reclaim_proc_ok", replyError: "reclaim_proc_error", writeOp: true, listener: function (data, callback) { reclaimProc_1.reclaimProc(db, activeProcs, data.procName, function (err, lastClaimedRange) { if (err) { callback((err && err.message) || "uknown_error"); } else { callback(null, { lastClaimedRange: lastClaimedRange ? tones_1.convertToClientId(lastClaimedRange) : "" }); } }); } }); const initIPCListener = function (e) { if (e.type === "init_ipc") { process.removeListener("message", initIPCListener); connectionAddress = e.data.address; clientTLS = e.data.tls && e.data.tls.client; messaging_1.initializeMessages(writeBuffer, messageRegistry, connectionAddress, e.data.tls && e.data.tls.server, function (err, socket) { if (err) { if (process && typeof process.send === "function") { process.send(messages_1.prepareMessage({ type: "ipc_established", msgKey: e.msgKey, errStatus: err.message })); } } else { serverSocket = socket; if (process && typeof process.send === "function") { process.send(messages_1.prepareMessage({ type: "ipc_established", msgKey: e.msgKey })); } } }); } }; const shutdownListener = function (e) { if (e.type === "system_shutdown") { d("shutting down..."); stopWriteBuffer(function () { if (serverSocket) { serverSocket.close(); } if (gcInterval) { d("stopping gc"); clearInterval(gcInterval); } process.removeListener("message", shutdownListener); shutdown_1.runShutdownHooks(db, systemState, activeWorkers, function (err) { if (err) { if (process && typeof process.send === "function") { process.send(messages_1.prepareMessage({ type: "system_closed_error", msgKey: e.msgKey, errStatus: (err && err.message) || "uknown_error" })); } } else { if (process && typeof process.send === "function") { process.send(messages_1.prepareMessage({ type: "system_closed", msgKey: e.msgKey })); } } }); }); } }; process.on("message", initIPCListener); process.on("message", shutdownListener); stopWriteBuffer = writeBuffer_1.startWriteBuffer(writeBuffer);