UNPKG

redis-smq

Version:

A simple high-performance Redis message queue for Node.js.

245 lines 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Producer = void 0; const redis_smq_common_1 = require("redis-smq-common"); const redis_client_js_1 = require("../../common/redis-client/redis-client.js"); 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("../event-bus/index.js"); const _get_exchange_queues_js_1 = require("../exchange/_/_get-exchange-queues.js"); const index_js_3 = require("../exchange/index.js"); const index_js_4 = require("../message/index.js"); const message_envelope_js_1 = require("../message/message-envelope.js"); const index_js_5 = require("../queue/index.js"); const _schedule_message_js_1 = require("./_/_schedule-message.js"); const index_js_6 = require("./errors/index.js"); const event_bus_publisher_js_1 = require("./event-bus-publisher.js"); const queue_consumer_groups_cache_js_1 = require("./queue-consumer-groups-cache.js"); class Producer extends redis_smq_common_1.Runnable { constructor() { super(); this.queueConsumerGroupsHandler = null; this.initQueueConsumerGroupsHandler = (cb) => { this.queueConsumerGroupsHandler = new queue_consumer_groups_cache_js_1.QueueConsumerGroupsCache(this, this.redisClient, this.eventBus, this.logger); this.queueConsumerGroupsHandler.run((err) => cb(err)); }; this.shutDownQueueConsumerGroupsHandler = (cb) => { if (this.queueConsumerGroupsHandler) { this.queueConsumerGroupsHandler.shutdown(() => { this.queueConsumerGroupsHandler = null; cb(); }); } else cb(); }; this.initRedisClient = (cb) => this.redisClient.getSetInstance((err, client) => { if (err) cb(err); else if (!client) cb(new redis_smq_common_1.CallbackEmptyReplyError()); else { client.on('error', (err) => this.handleError(err)); cb(); } }); this.redisClient = new redis_client_js_1.RedisClient(); this.redisClient.on('error', (err) => this.handleError(err)); this.eventBus = new index_js_2.EventBus(); this.eventBus.on('error', (err) => this.handleError(err)); this.logger = redis_smq_common_1.logger.getLogger(index_js_1.Configuration.getSetConfig().logger, `producer:${this.id}`); if (index_js_1.Configuration.getSetConfig().eventBus.enabled) { (0, event_bus_publisher_js_1.eventBusPublisher)(this, this.eventBus, this.logger); } } getLogger() { return this.logger; } goingUp() { return super.goingUp().concat([ this.redisClient.init, this.eventBus.init, (cb) => { this.emit('producer.goingUp', this.id); cb(); }, this.initRedisClient, this.initQueueConsumerGroupsHandler, ]); } up(cb) { super.up(() => { this.emit('producer.up', this.id); cb(null, true); }); } goingDown() { this.emit('producer.goingDown', this.id); return [ this.shutDownQueueConsumerGroupsHandler, this.redisClient.shutdown, ].concat(super.goingDown()); } down(cb) { super.down(() => { this.emit('producer.down', this.id); setTimeout(() => this.eventBus.shutdown(() => cb(null, true)), 1000); }); } getQueueConsumerGroupsHandler() { if (!this.queueConsumerGroupsHandler) throw new redis_smq_common_1.PanicError(`Expected an instance of QueueConsumerGroupsHandler`); return this.queueConsumerGroupsHandler; } enqueue(redisClient, message, cb) { var _a; const messageState = message.getMessageState(); messageState.setPublishedAt(Date.now()); const messageId = message.getId(); const keys = redis_keys_js_1.redisKeys.getQueueKeys(message.getDestinationQueue(), message.getConsumerGroupId()); const { keyMessage } = redis_keys_js_1.redisKeys.getMessageKeys(messageId); const scriptArgs = [ index_js_5.EQueueProperty.QUEUE_TYPE, index_js_5.EQueueProperty.MESSAGES_COUNT, index_js_5.EQueueType.PRIORITY_QUEUE, index_js_5.EQueueType.LIFO_QUEUE, index_js_5.EQueueType.FIFO_QUEUE, (_a = message.producibleMessage.getPriority()) !== null && _a !== void 0 ? _a : '', messageId, index_js_4.EMessageProperty.STATUS, index_js_4.EMessagePropertyStatus.PENDING, index_js_4.EMessageProperty.STATE, JSON.stringify(messageState), index_js_4.EMessageProperty.MESSAGE, JSON.stringify(message.toJSON()), ]; redisClient.runScript(scripts_js_1.ELuaScriptName.PUBLISH_MESSAGE, [ keys.keyQueueProperties, keys.keyQueuePriorityPending, keys.keyQueuePending, keys.keyQueueMessages, keyMessage, ], scriptArgs, (err, reply) => { if (err) return cb(err); switch (reply) { case 'OK': return cb(); case 'QUEUE_NOT_FOUND': return cb(new index_js_6.ProducerQueueNotFoundError()); case 'MESSAGE_PRIORITY_REQUIRED': return cb(new index_js_6.ProducerMessagePriorityRequiredError()); case 'PRIORITY_QUEUING_NOT_ENABLED': return cb(new index_js_6.ProducerPriorityQueuingNotEnabledError()); case 'UNKNOWN_QUEUE_TYPE': return cb(new index_js_6.ProducerUnknownQueueTypeError()); default: return cb(new index_js_6.ProducerError()); } }); } produceMessageItem(redisClient, message, queue, cb) { const messageId = message .setDestinationQueue(queue) .getMessageState() .getId(); const handleResult = (err) => { if (err) { cb(err); } else { const action = message.isSchedulable() ? 'scheduled' : 'published'; this.logger.info(`Message (ID ${messageId}) has been ${action}.`); if (!message.isSchedulable()) { this.emit('producer.messagePublished', messageId, { queueParams: queue, groupId: message.getConsumerGroupId() }, this.id); } cb(null, messageId); } }; if (message.isSchedulable()) { (0, _schedule_message_js_1._scheduleMessage)(redisClient, message, handleResult); } else { this.enqueue(redisClient, message, handleResult); } } produceMessage(redisClient, message, queue, cb) { const { exists, consumerGroups } = this.getQueueConsumerGroupsHandler().getConsumerGroups(queue); if (exists) { if (!consumerGroups.length) { cb(new index_js_6.ProducerQueueMissingConsumerGroupsError()); } const ids = []; redis_smq_common_1.async.eachOf(consumerGroups, (group, _, done) => { const msg = new message_envelope_js_1.MessageEnvelope(message).setConsumerGroupId(group); this.produceMessageItem(redisClient, msg, queue, (err, reply) => { if (err) done(err); else { ids.push(String(reply)); done(); } }); }, (err) => { if (err) cb(err); else cb(null, ids); }); } else { const msg = new message_envelope_js_1.MessageEnvelope(message); this.produceMessageItem(redisClient, msg, queue, (err, reply) => { if (err) cb(err); else cb(null, [String(reply)]); }); } } produce(msg, cb) { if (!this.isUp()) { return cb(new index_js_6.ProducerInstanceNotRunningError()); } const redisClient = this.redisClient.getInstance(); if (redisClient instanceof Error) { return cb(redisClient); } const exchangeParams = msg.getExchange(); if (!exchangeParams) { return cb(new index_js_6.ProducerMessageExchangeRequiredError()); } if (exchangeParams.type === index_js_3.EExchangeType.DIRECT) { const queue = exchangeParams.params; return this.produceMessage(redisClient, msg, queue, cb); } (0, _get_exchange_queues_js_1._getExchangeQueues)(redisClient, exchangeParams, (err, queues) => { if (err) { return cb(err); } if (!(queues === null || queues === void 0 ? void 0 : queues.length)) { return cb(new index_js_6.ProducerExchangeNoMatchedQueueError()); } const messages = []; redis_smq_common_1.async.eachOf(queues, (queue, index, done) => { this.produceMessage(redisClient, msg, queue, (err, reply) => { if (err) { return done(err); } if (reply) { messages.push(...reply); } done(); }); }, (err) => { if (err) { return cb(err); } cb(null, messages); }); }); } } exports.Producer = Producer; //# sourceMappingURL=producer.js.map