UNPKG

reliable-zeromq

Version:

A collection of reliable zeromq messaging constructs

162 lines 12.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZMQResponse = exports.RESPONSE_CACHE_EXPIRED = void 0; const typescript_collections_1 = require("typescript-collections"); const zmq = __importStar(require("zeromq")); const Config_1 = __importDefault(require("./Config")); const Errors_1 = require("./Errors"); const ExpiryMap_1 = __importDefault(require("./Utils/ExpiryMap")); const NonceMap_1 = require("./Utils/NonceMap"); const ZMQRequest_1 = require("./ZMQRequest"); exports.RESPONSE_CACHE_EXPIRED = "ZMQ_RESPONSE ERROR: MESSAGE NOT IN CACHE"; class ZMQResponse { constructor(aReplierEndpoint, aReceiver, aErrorHandlers) { this.mSafeToSend = true; this.mSeenMessages = new Map(); this.mSendQueue = new typescript_collections_1.Queue(); this.mCachedRequests = new ExpiryMap_1.default(3 * Config_1.default.MaximumLatency); // 3 times latency assumption, this is a bit arbitrary this.mEndpoint = aReplierEndpoint; this.mRequestHandler = aReceiver; this.mErrorHandlers = aErrorHandlers ?? Errors_1.DEFAULT_ZMQ_RESPONSE_ERROR_HANDLERS; this.Open(); } get Endpoint() { return this.mEndpoint; } static GetCacheId(lSenderUID, nonce) { return lSenderUID + nonce.toString(); } HandleDuplicateRequest(aSenderUID, routing_id, nonce) { const lCacheId = ZMQResponse.GetCacheId(aSenderUID, nonce); const lCachedResponse = this.mCachedRequests.get(lCacheId); if (typeof lCachedResponse === "string") { this.QueueSend({ Requester: aSenderUID, Response: [routing_id, nonce, lCachedResponse], }); } else if (lCachedResponse === undefined) { this.QueueSend({ Requester: aSenderUID, Response: [routing_id, nonce, exports.RESPONSE_CACHE_EXPIRED], }); } } HandleNewRequest(sender_uid, nonce, msg, routing_id) { const lSenderUID = sender_uid.toString(); const lMessageId = ZMQResponse.GetCacheId(lSenderUID, nonce); const lPromise = this.mRequestHandler(msg.toString()); this.mCachedRequests.set(lMessageId, lPromise); // WARN: Timer starts from when promise is inserted, this will cause issues if we move to an req, ack, rep model lPromise.then((aResponse) => { this.mCachedRequests.set(lMessageId, aResponse); this.QueueSend({ Requester: lSenderUID, Response: [routing_id, nonce, aResponse], }); }); } HandleRequest(sender_uid, nonce, msg, routing_id) { const lSenderUID = sender_uid.toString(); const lNonce = Number(nonce.toString()); if (this.UnseenRequest(lSenderUID, lNonce)) { this.UpdateSeenMessages(lSenderUID, lNonce); this.HandleNewRequest(sender_uid, nonce, msg, routing_id); } else { this.HandleDuplicateRequest(lSenderUID, routing_id, nonce); } } HandleZMQSendError(aError, aRequest) { if (aError && aError.code && aError.code === "EAGAIN") { const lHighWaterMarkWarning = { Requester: aRequest.Requester, Nonce: Number(aRequest.Response[ZMQRequest_1.ERequestBody.Nonce]), Message: aRequest.Response[ZMQRequest_1.ERequestBody.Message], }; this.mErrorHandlers.HighWaterMarkWarning(lHighWaterMarkWarning); } else { throw aError; } } InitRequesterIfEmpty(aSenderUID) { if (!this.mSeenMessages.has(aSenderUID)) { this.mSeenMessages.set(aSenderUID, new NonceMap_1.NonceMap()); } } Open() { this.mRouter = new zmq.Router(); this.mRouter.mandatory = true; this.mRouter.bind(this.mEndpoint) .then(() => { this.ReceiveLoop(); }); } async ProcessSend() { const lNextSend = this.mSendQueue.peek(); if (lNextSend && this.mSafeToSend) { this.mSafeToSend = false; this.mSendQueue.dequeue(); try { await this.mRouter.send(lNextSend.Response); } catch (aError) { this.HandleZMQSendError(aError, lNextSend); } this.mSafeToSend = true; this.ProcessSend(); } } QueueSend(aRequest) { this.mSendQueue.enqueue(aRequest); this.ProcessSend(); } async ReceiveLoop() { for await (const [routing_id, sender_uid, nonce, msg] of this.mRouter) { if (this.mRouter) { const lSenderUID = sender_uid.toString(); this.InitRequesterIfEmpty(lSenderUID); this.HandleRequest(sender_uid, nonce, msg, routing_id); } } } UnseenRequest(aSenderUID, aNonce) { return !this.mSeenMessages.get(aSenderUID).Has(aNonce); } UpdateSeenMessages(aSenderUID, aNewNonce) { const lNonces = this.mSeenMessages.get(aSenderUID); lNonces.Insert(aNewNonce); lNonces.GarbageClean(); } Close() { this.mCachedRequests.clear(); this.mSeenMessages.clear(); this.mRouter.linger = 0; this.mRouter.close(); this.mRouter = undefined; } } exports.ZMQResponse = ZMQResponse; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiWk1RUmVzcG9uc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9TcmMvWk1RUmVzcG9uc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1FQUErQztBQUMvQyw0Q0FBOEI7QUFDOUIsc0RBQThCO0FBQzlCLHFDQUlrQjtBQUNsQixrRUFBMEM7QUFDMUMsK0NBQTRDO0FBQzVDLDZDQUE0QztBQUUvQixRQUFBLHNCQUFzQixHQUFXLDBDQUEwQyxDQUFDO0FBU3pGLE1BQWEsV0FBVztJQVdwQixZQUNJLGdCQUF3QixFQUN4QixTQUFnRCxFQUNoRCxjQUEwQztRQVB0QyxnQkFBVyxHQUFZLElBQUksQ0FBQztRQUNuQixrQkFBYSxHQUEwQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ2pELGVBQVUsR0FBMkIsSUFBSSw4QkFBSyxFQUFFLENBQUM7UUFROUQsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLG1CQUFTLENBQUMsQ0FBQyxHQUFHLGdCQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBSSxzREFBc0Q7UUFDMUgsSUFBSSxDQUFDLFNBQVMsR0FBRyxnQkFBZ0IsQ0FBQztRQUNsQyxJQUFJLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQztRQUNqQyxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsSUFBSSw0Q0FBbUMsQ0FBQztRQUU1RSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDaEIsQ0FBQztJQUVELElBQVcsUUFBUTtRQUVmLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUMxQixDQUFDO0lBRU8sTUFBTSxDQUFDLFVBQVUsQ0FBQyxVQUFrQixFQUFFLEtBQWE7UUFFdkQsT0FBTyxVQUFVLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3pDLENBQUM7SUFFTyxzQkFBc0IsQ0FBQyxVQUFrQixFQUFFLFVBQWtCLEVBQUUsS0FBYTtRQUVoRixNQUFNLFFBQVEsR0FBVyxX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