reliable-zeromq
Version:
A collection of reliable zeromq messaging constructs
162 lines • 12.6 kB
JavaScript
"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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