trade360-nodejs-sdk
Version:
LSports Trade360 SDK for Node.js
179 lines • 7.98 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageConsumer = void 0;
const lodash_1 = require("lodash");
const _entities_1 = require("../../../entities/core-entities/index.js");
const _utilities_1 = require("../../../utilities");
const handler_1 = require("./handler");
/**
* Convert json string to WrappedMessage instance
* @param rawJson json string to be converted to
* WrappedMessage instance
* @returns WrappedMessage instance from the json
* string provided
*/
function ConvertJsonToMessage(rawJson) {
try {
const parsedData = _utilities_1.IdSafeJsonParser.parse(rawJson);
const message = _utilities_1.TransformerUtil.transform(parsedData, _entities_1.WrappedMessage);
return message;
}
catch (err) {
throw new _entities_1.ConversionError(_entities_1.WrappedMessage.name, err);
}
}
/**
* Class that represent message consumption process
* and handle them with all the configured desired
* handlers for entities types and process them with
* the entityHandler call-back function for the
* entityConstructor class type entity type and process
* them with the entityHandler call-back function for
* the entityConstructor class type entity type and
* check message consumption latency and log warning
* if it exceeds the threshold value in seconds or log
* info if it's within the threshold value in seconds
*/
class MessageConsumer {
constructor(logger) {
this.logger = logger;
this.bodyHandlers = new Map();
}
/**
* Handle basic message consumption process and handle
* them with all the configured desired handlers for
* entities types and process them with the entityHandler
* call-back function for the entityConstructor class type
* entity type and check message consumption latency and
* log warning if it exceeds the threshold value in seconds
* or log info if it's within the threshold value in seconds
* @param messageContent message content to be consumed and
* processed by the configured entity handlers for the entity
* type and entity handler call-back function for the entity
* constructor class type entity type
* @param messageMqTimestamp message timestamp in milliseconds
* to calculate the message consumption latency in seconds
* @param consumptionLatencyThreshold consumption latency
* threshold in seconds to check if the message consumption
* latency exceeds the threshold value in seconds or not
* @returns void
*/
async handleBasicMessage(messageContent, { messageMqTimestamp, consumptionLatencyThreshold }, transportHeaders) {
try {
if (this.bodyHandlers.size == 0) {
this.logger?.warn('there is no configured entities handler, please config at least one');
return;
}
const rawMessage = messageContent.toString();
const { header, body } = ConvertJsonToMessage(rawMessage);
if ((0, lodash_1.isNil)(messageMqTimestamp)) {
this.logger?.warn('message property timestamp_in_ms was not provided by message broker');
}
else {
header.messageBrokerTimestamp = messageMqTimestamp;
}
if ((0, lodash_1.isNil)(header)) {
this.logger?.warn('invalid message format');
return;
}
const { type: entityType, msgGuid } = header;
const bodyHandler = this.bodyHandlers.get(entityType);
if (!(0, lodash_1.isNil)(bodyHandler)) {
await bodyHandler.processAsync({ header, body, transportHeaders });
this.checkConsumptionLatency({
messageMqTimestamp,
consumptionLatencyThreshold,
msgGuid,
});
}
else {
const missedEntityType = _entities_1.knownEntityKeys.get(entityType);
if (!(0, lodash_1.isNil)(missedEntityType)) {
// HeartbeatUpdate (entityKey 32) is handled automatically by the SDK, suppress warning
if (entityType !== 32) {
this.logger?.warn(`entity handler for ${missedEntityType} is not configured`);
}
}
else {
this.logger?.warn(`received unknown entity type ${entityType}`);
}
return;
}
}
catch (err) {
if (err instanceof _entities_1.ConversionError) {
this.logger?.warn(`Failed to deserialise message: ${err}`);
return;
}
this.logger?.error(`Error handling message consumption, error: ${err}`);
throw err;
}
}
/**
* Check message consumption latency and log warning if it
* exceeds the threshold value in seconds or log info if
* it's within the threshold value in seconds. If message or
* threshold is missing, log warning message with the message
* guid provided in the input object parameter and return void
* @param messageMqTimestamp message timestamp in milliseconds
* to calculate the message consumption latency in seconds
* @param consumptionLatencyThreshold consumption latency
* threshold in seconds to check if the message consumption
* latency exceeds the threshold value in seconds or not
* @param msgGuid message guid to be logged in the warning
* message if the message or threshold is missing
* @returns void
*/
checkConsumptionLatency({ messageMqTimestamp, consumptionLatencyThreshold: thresholdInSeconds, msgGuid, }) {
if ((0, lodash_1.isNil)(messageMqTimestamp) || (0, lodash_1.isNil)(thresholdInSeconds)) {
this.logger.warn('Unable to check message consumption delay: missing message timestamp or threshold', { msgGuid });
}
else {
const consumptionTimestamp = Date.now();
const delayInSeconds = (consumptionTimestamp - messageMqTimestamp) / 1000;
if (delayInSeconds > thresholdInSeconds) {
this.logger.warn('Message consumption delay exceeded threshold', {
delayInSeconds,
thresholdInSeconds,
messageMqTimestamp,
consumptionTimestamp,
msgGuid,
});
}
else {
this.logger.info('Message consumed within threshold', {
delayInSeconds,
thresholdInSeconds,
msgGuid,
});
}
}
}
/**
* Register new entity handler for specific entity type
* @param entityHandler entity handler instance that implement
* IEntityHandler interface
* @param entityConstructor entity constructor that extends
* BaseEntity class and has entityKey property in its prototype
* @throws Error if entityConstructor is not a trade360 entity
* or if there is an error setting registration for new entity
* handler
* @returns void
*/
RegisterEntityHandler(entityHandler, entityConstructor) {
try {
const { name, prototype: { entityKey }, } = entityConstructor;
if (!entityKey) {
throw new Error(`${name} isn't trade360 entity. You should use only entities from Trade360SDK!`);
}
const newBodyHandler = new handler_1.BodyHandler(entityHandler, entityConstructor, this.logger);
this.bodyHandlers.set(entityKey, newBodyHandler);
}
catch (err) {
this.logger?.error(`Error setting registration for new entity handler, error: ${err}`);
throw err;
}
}
}
exports.MessageConsumer = MessageConsumer;
//# sourceMappingURL=message-consumer.js.map