redis-smq
Version:
A simple high-performance Redis message queue for Node.js.
181 lines • 8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConsumeMessage = void 0;
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const redis_smq_common_1 = require("redis-smq-common");
const scripts_js_1 = require("../../../../common/redis-client/scripts/scripts.js");
const redis_keys_js_1 = require("../../../../common/redis-keys/redis-keys.js");
const index_js_1 = require("../../../../config/index.js");
const index_js_2 = require("../../../message/index.js");
const index_js_3 = require("../../types/index.js");
const index_js_4 = require("../errors/index.js");
const processing_queue_js_1 = require("../processing-queue/processing-queue.js");
const event_bus_publisher_js_1 = require("./event-bus-publisher.js");
class ConsumeMessage extends redis_smq_common_1.Runnable {
constructor(redisClient, consumer, queue, messageHandlerId, messageHandler, logger, eventBus) {
super();
this.consumeMessageWorker = null;
this.validateMessageHandler = (cb) => {
if (typeof this.messageHandler === 'string') {
if (!['.js', '.cjs'].includes(path_1.default.extname(this.messageHandler))) {
cb(new index_js_4.ConsumerMessageHandlerFilenameExtensionError());
}
else
(0, fs_1.stat)(this.messageHandler, (err) => {
if (err)
cb(new index_js_4.ConsumerMessageHandlerFileError());
else
cb();
});
}
else
cb();
};
this.queue = queue;
this.consumerId = consumer.getId();
this.messageHandler = messageHandler;
this.messageHandlerId = messageHandlerId;
this.redisClient = redisClient;
const { keyQueueProcessing } = redis_keys_js_1.redisKeys.getQueueConsumerKeys(this.queue.queueParams, this.consumerId);
const { keyQueueAcknowledged } = redis_keys_js_1.redisKeys.getQueueKeys(this.queue.queueParams, this.queue.groupId);
this.keyQueueAcknowledged = keyQueueAcknowledged;
this.keyQueueProcessing = keyQueueProcessing;
this.logger = logger;
if (eventBus) {
(0, event_bus_publisher_js_1.eventBusPublisher)(this, eventBus, logger);
}
}
getLogger() {
return this.logger;
}
acknowledgeMessage(message) {
const messageId = message.getId();
const { store, queueSize, expire } = index_js_1.Configuration.getSetConfig().messages.store.acknowledged;
const { keyMessage } = redis_keys_js_1.redisKeys.getMessageKeys(messageId);
const redisClient = this.redisClient.getInstance();
if (redisClient instanceof Error) {
this.handleError(redisClient);
return void 0;
}
redisClient.runScript(scripts_js_1.ELuaScriptName.ACKNOWLEDGE_MESSAGE, [this.keyQueueProcessing, this.keyQueueAcknowledged, keyMessage], [
index_js_2.EMessageProperty.STATUS,
index_js_2.EMessagePropertyStatus.ACKNOWLEDGED,
Number(store),
expire,
queueSize * -1,
], (err) => {
if (err)
this.handleError(err);
else {
this.emit('consumer.consumeMessage.messageAcknowledged', messageId, this.queue, this.messageHandlerId, this.consumerId);
}
});
}
unacknowledgeMessage(msg, unknowledgmentReason) {
const redisClient = this.redisClient.getInstance();
if (redisClient instanceof Error) {
this.handleError(redisClient);
return void 0;
}
processing_queue_js_1.processingQueue.unknowledgeMessage(redisClient, this.consumerId, [this.queue.queueParams], this.logger, unknowledgmentReason, (err, reply) => {
if (err)
this.handleError(err);
else if (!reply)
this.handleError(new redis_smq_common_1.CallbackEmptyReplyError());
else {
const messageId = msg.getId();
this.emit('consumer.consumeMessage.messageUnacknowledged', messageId, this.queue, this.messageHandlerId, this.consumerId, unknowledgmentReason);
const unknowledgment = reply[messageId];
if (unknowledgment.action === index_js_3.EMessageUnknowledgmentAction.DEAD_LETTER) {
this.emit('consumer.consumeMessage.messageDeadLettered', messageId, this.queue, this.messageHandlerId, this.consumerId, unknowledgment.deadLetterReason);
}
else if (unknowledgment.action === index_js_3.EMessageUnknowledgmentAction.DELAY) {
this.emit('consumer.consumeMessage.messageDelayed', messageId, this.queue, this.messageHandlerId, this.consumerId);
}
else {
this.emit('consumer.consumeMessage.messageRequeued', messageId, this.queue, this.messageHandlerId, this.consumerId);
}
}
});
}
getConsumeMessageWorker(messageHandlerFilename) {
if (!this.consumeMessageWorker) {
this.consumeMessageWorker = new redis_smq_common_1.WorkerCallable(messageHandlerFilename);
}
return this.consumeMessageWorker;
}
invokeMessageHandler(messageHandler, msg, cb) {
if (typeof messageHandler === 'string') {
this.getConsumeMessageWorker(messageHandler).call(msg, cb);
}
else
messageHandler(msg, cb);
}
consumeMessage(msg) {
let isTimeout = false;
let timer = null;
try {
const consumeTimeout = msg.producibleMessage.getConsumeTimeout();
if (consumeTimeout) {
timer = setTimeout(() => {
isTimeout = true;
timer = null;
this.unacknowledgeMessage(msg, index_js_3.EMessageUnknowledgmentReason.TIMEOUT);
}, consumeTimeout);
}
const onConsumed = (err) => {
if (this.isRunning() && !isTimeout) {
if (timer)
clearTimeout(timer);
if (err) {
this.logger.error(err);
this.unacknowledgeMessage(msg, index_js_3.EMessageUnknowledgmentReason.UNACKNOWLEDGED);
}
else {
this.acknowledgeMessage(msg);
}
}
};
this.invokeMessageHandler(this.messageHandler, msg.transfer(), onConsumed);
}
catch (error) {
this.logger.error(error);
this.unacknowledgeMessage(msg, index_js_3.EMessageUnknowledgmentReason.CONSUME_ERROR);
}
}
goingUp() {
return super
.goingUp()
.concat([this.redisClient.init, this.validateMessageHandler]);
}
goingDown() {
return [
(cb) => {
if (this.consumeMessageWorker) {
this.consumeMessageWorker.shutdown(cb);
}
else
cb();
},
].concat(super.goingDown());
}
handleError(err) {
this.emit('consumer.consumeMessage.error', err, this.consumerId, this.queue);
super.handleError(err);
}
handleReceivedMessage(message) {
if (this.isRunning()) {
if (message.getSetExpired()) {
this.unacknowledgeMessage(message, index_js_3.EMessageUnknowledgmentReason.TTL_EXPIRED);
}
else
this.consumeMessage(message);
}
}
}
exports.ConsumeMessage = ConsumeMessage;
//# sourceMappingURL=consume-message.js.map