UNPKG

@axinom/mosaic-transactional-inbox-outbox

Version:

This library encapsulates the Mosaic based transactional inbox and outbox pattern

133 lines 6.63 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RabbitMqInboxWriter = void 0; const mosaic_message_bus_1 = require("@axinom/mosaic-message-bus"); const async_mutex_1 = require("async-mutex"); const common_1 = require("../common"); class RabbitMqInboxWriter extends mosaic_message_bus_1.MessageHandler { /** * Creates a new RabbitMQ-based handler that receives all events and commands * and stores them in the transactional inbox. * @param storeInboxMessage Function to store the incoming RabbitMQ message in the transactional inbox * @param customizations Provide custom logic on how the inbox writer should process messages */ constructor(storeInboxMessage, ownerPool, logger, customizations) { super(common_1.DEFAULT_INBOX_MESSAGE_TYPE); this.storeInboxMessage = storeInboxMessage; this.ownerPool = ownerPool; this.logger = logger; this.mutex = new async_mutex_1.Mutex(); //TODO: [feature/image-transactional-in-out-box] remove backwards compatibility after 2024-02-01 this.backwardCompatibilityMapper = (acceptedMessageSettings) => { const backwardCompatibilityMappings = {}; for (const messageSettings of acceptedMessageSettings !== null && acceptedMessageSettings !== void 0 ? acceptedMessageSettings : []) { backwardCompatibilityMappings[messageSettings.messageType] = messageSettings.aggregateType; } return backwardCompatibilityMappings; }; this.customMessageMapper = customizations === null || customizations === void 0 ? void 0 : customizations.customMessageMapper; this.customMessagePreProcessor = customizations === null || customizations === void 0 ? void 0 : customizations.customMessagePreProcessor; this.backwardCompatibilityMappings = this.backwardCompatibilityMapper(customizations === null || customizations === void 0 ? void 0 : customizations.acceptedMessageSettings); } /** * Store the incoming message in the transactional inbox. */ async onMessage(payload, message) { var _a, _b, _c; // Using a mutex to ensure that each message is completely inserted // in the original sort order into the inbox. const release = await this.mutex.acquire(); let msgInput; try { if (this.customMessageMapper) { msgInput = this.customMessageMapper(message); } if (!msgInput) { const envelope = message.envelope; let aggregateType = envelope.aggregate_type; if (!aggregateType) { //TODO: [feature/image-transactional-in-out-box] remove backwards compatibility after 2024-02-01 aggregateType = (_a = this.backwardCompatibilityMappings[envelope.message_type]) !== null && _a !== void 0 ? _a : common_1.UNKNOWN_AGGREGATE_TYPE; } let aggregateId = envelope.aggregate_id; if (!aggregateId) { //TODO: [feature/image-transactional-in-out-box] remove backwards compatibility after 2024-02-01 aggregateId = String((_b = payload === null || payload === void 0 ? void 0 : payload.id) !== null && _b !== void 0 ? _b : common_1.UNKNOWN_AGGREGATE_ID); } msgInput = { messageId: envelope.message_id, aggregateId, messagingSettings: { aggregateType, messageType: envelope.message_type, }, payload, metadata: { envelopeTimestamp: envelope.timestamp, messageVersion: envelope.message_version, messageContext: envelope.message_context, authToken: envelope.auth_token, fields: message.fields, properties: message.properties, }, concurrency: 'parallel', segment: unsafeGetEnvironment(envelope.auth_token), }; } (_c = this.customMessagePreProcessor) === null || _c === void 0 ? void 0 : _c.call(this, msgInput); const { payload: p, aggregateId, messagingSettings } = msgInput, optionalData = __rest(msgInput, ["payload", "aggregateId", "messagingSettings"]); // No transaction for single insert needed - directly using the pool await this.storeInboxMessage(aggregateId, messagingSettings, p, this.ownerPool, optionalData); this.logger.debug({ message: 'Message added to the inbox table.', details: Object.assign({}, msgInput), }); } catch (error) { const err = error instanceof Error ? error : new Error(String(error !== null && error !== void 0 ? error : 'unknown error')); this.logger.error(err, { message: 'Could not write the message to the inbox table.', details: Object.assign({}, (msgInput !== null && msgInput !== void 0 ? msgInput : message)), }); throw err; } finally { release(); } } } exports.RabbitMqInboxWriter = RabbitMqInboxWriter; /** * Get the environment ID by parsing the JWT without checking the signature. * This is only used for "fair message processing" - the actual JWT check is * done in the message handler. */ const unsafeGetEnvironment = (token) => { var _a; if (!token) { return undefined; } try { const parsed = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); return (_a = parsed === null || parsed === void 0 ? void 0 : parsed.environmentId) !== null && _a !== void 0 ? _a : undefined; } catch (_b) { return undefined; } }; //# sourceMappingURL=rabbitmq-inbox-writer.js.map