redis-smq
Version:
A simple high-performance Redis message queue for Node.js.
175 lines • 8.17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageHandlerRunner = void 0;
const redis_smq_common_1 = require("redis-smq-common");
const index_js_1 = require("../../../config/index.js");
const index_js_2 = require("../errors/index.js");
const message_handler_js_1 = require("../message-handler/message-handler/message-handler.js");
const event_bus_publisher_js_1 = require("./event-bus-publisher.js");
class MessageHandlerRunner extends redis_smq_common_1.Runnable {
constructor(consumer, redisClient, eventBus) {
super();
this.messageHandlerInstances = [];
this.messageHandlers = [];
this.runMessageHandlers = (cb) => {
const handlerCount = this.messageHandlers.length;
this.logger.info(`Starting ${handlerCount} message handler(s)`);
if (handlerCount === 0)
return cb();
redis_smq_common_1.async.each(this.messageHandlers, (handlerParams, _, done) => {
this.runMessageHandler(handlerParams, done);
}, (err) => {
if (err) {
this.logger.error(`Error starting message handlers: ${err.message}`);
}
else {
this.logger.info(`All message handlers started`);
}
cb(err);
});
};
this.shutDownMessageHandlers = (cb) => {
const handlerCount = this.messageHandlerInstances.length;
this.logger.info(`Shutting down ${handlerCount} message handler(s)`);
if (handlerCount === 0)
return cb();
redis_smq_common_1.async.each(this.messageHandlerInstances, (handler, _, done) => {
this.shutdownMessageHandler(handler, done);
}, () => {
this.messageHandlerInstances = [];
this.logger.info('All message handlers have been shut down');
cb();
});
};
this.consumer = consumer;
this.redisClient = redisClient;
this.logger = redis_smq_common_1.logger.getLogger(index_js_1.Configuration.getSetConfig().logger, this.constructor.name.toLowerCase());
this.logger.info(`Initializing MessageHandlerRunner with ID: ${this.id}`);
this.eventBus = eventBus;
if (this.eventBus) {
this.logger.debug('Event bus provided, setting up event bus publisher');
(0, event_bus_publisher_js_1.eventBusPublisher)(this, this.eventBus, this.logger);
}
this.logger.debug(`MessageHandlerRunner initialized for consumer ID: ${this.consumer.getId()}`);
}
getLogger() {
return this.logger;
}
getMessageHandlerInstance(queue) {
return this.messageHandlerInstances.find((i) => {
const handlerQueue = i.getQueue();
return (handlerQueue.queueParams.name === queue.queueParams.name &&
handlerQueue.queueParams.ns === queue.queueParams.ns &&
handlerQueue.groupId === queue.groupId);
});
}
getMessageHandler(queue) {
return this.messageHandlers.find((i) => i.queue.queueParams.name === queue.queueParams.name &&
i.queue.queueParams.ns === queue.queueParams.ns &&
i.queue.groupId === queue.groupId);
}
createMessageHandlerInstance(handlerParams) {
const instance = new message_handler_js_1.MessageHandler(this.consumer, this.redisClient, handlerParams, true, this.eventBus);
instance.on('consumer.messageHandler.error', (err, consumerId, queue) => {
this.logger.error(`MessageHandler error from consumer ${consumerId} for queue ${JSON.stringify(queue)}: ${err.message}`);
this.removeMessageHandler(queue, () => {
this.logger.error(`Error in MessageHandler: ${err.message}`, err);
});
});
this.messageHandlerInstances.push(instance);
this.logger.info(`Created MessageHandler (ID: ${instance.getId()}) for queue: ${handlerParams.queue.queueParams.name}. Total: ${this.messageHandlerInstances.length}`);
return instance;
}
runMessageHandler(handlerParams, cb) {
const handler = this.createMessageHandlerInstance(handlerParams);
handler.run((err) => {
if (err) {
this.logger.error(`Failed to run message handler: ${err.message}`);
this.removeMessageHandler(handlerParams.queue, () => cb(err));
}
else {
this.logger.debug(`Message handler started for queue: ${handlerParams.queue.queueParams.name}`);
cb();
}
});
}
shutdownMessageHandler(messageHandler, cb) {
const queue = messageHandler.getQueue();
messageHandler.shutdown((err) => {
if (err) {
this.logger.warn(`Error during message handler shutdown (ignored): ${err.message}`);
}
const beforeCount = this.messageHandlerInstances.length;
this.messageHandlerInstances = this.messageHandlerInstances.filter((handler) => {
const iQueue = handler.getQueue();
return !(iQueue.queueParams.name === queue.queueParams.name &&
iQueue.queueParams.ns === queue.queueParams.ns &&
iQueue.groupId === queue.groupId);
});
const afterCount = this.messageHandlerInstances.length;
this.logger.debug(`Removed ${beforeCount - afterCount} message handler instance(s). Remaining: ${afterCount}`);
cb();
});
}
goingUp() {
this.logger.info('MessageHandlerRunner going up');
return super.goingUp().concat([this.runMessageHandlers]);
}
goingDown() {
this.logger.info('MessageHandlerRunner going down');
return [this.shutDownMessageHandlers].concat(super.goingDown());
}
handleError(err) {
if (this.isRunning()) {
this.logger.error(`MessageHandlerRunner error: ${err.message}`, err);
this.emit('consumer.messageHandlerRunner.error', err, this.consumer.getId());
}
super.handleError(err);
}
removeMessageHandler(queue, cb) {
const handler = this.getMessageHandler(queue);
if (!handler) {
this.logger.debug(`No message handler found for queue: ${queue.queueParams.name}, nothing to remove`);
return cb();
}
const beforeCount = this.messageHandlers.length;
this.messageHandlers = this.messageHandlers.filter((h) => {
const q = h.queue;
return !(queue.queueParams.name === q.queueParams.name &&
queue.queueParams.ns === q.queueParams.ns &&
queue.groupId === q.groupId);
});
const afterCount = this.messageHandlers.length;
this.logger.info(`Message handler for queue (${queue.queueParams.name}) removed. Removed ${beforeCount - afterCount} configuration(s).`);
const handlerInstance = this.getMessageHandlerInstance(queue);
if (handlerInstance) {
this.shutdownMessageHandler(handlerInstance, cb);
}
else {
cb();
}
}
addMessageHandler(queue, messageHandler, cb) {
if (this.getMessageHandler(queue)) {
this.logger.warn(`Message handler for queue ${queue.queueParams.name} already exists`);
return cb(new index_js_2.ConsumerConsumeMessageHandlerAlreadyExistsError());
}
const handlerParams = {
queue,
messageHandler,
};
this.messageHandlers.push(handlerParams);
this.logger.info(`Message handler registered for queue: ${queue.queueParams.name}. Total handlers: ${this.messageHandlers.length}`);
if (this.isRunning()) {
this.runMessageHandler(handlerParams, cb);
}
else {
cb();
}
}
getQueues() {
return this.messageHandlers.map((i) => i.queue);
}
}
exports.MessageHandlerRunner = MessageHandlerRunner;
//# sourceMappingURL=message-handler-runner.js.map