redis-smq
Version:
A high-performance, reliable, and scalable message queue for Node.js.
168 lines • 8.91 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PubSubTargetResolver = void 0;
const redis_smq_common_1 = require("redis-smq-common");
const _get_consumer_groups_js_1 = require("../consumer-groups/_/_get-consumer-groups.js");
const _get_queue_properties_js_1 = require("../queue-manager/_/_get-queue-properties.js");
const _get_queues_js_1 = require("../queue-manager/_/_get-queues.js");
const index_js_1 = require("../queue-manager/index.js");
const with_shared_pool_connection_js_1 = require("../common/redis/redis-connection-pool/with-shared-pool-connection.js");
const internal_event_bus_js_1 = require("../event-bus/internal-event-bus.js");
class PubSubTargetResolver extends redis_smq_common_1.Runnable {
constructor(producer, logger) {
super();
this.pubSubTargets = {};
this.onConsumerGroupCreated = (queue, groupId) => {
const queueKey = this.getQueueKey(queue);
this.logger.debug(`Handling 'consumerGroupCreated' event for group [${groupId}] on queue [${queueKey}]`);
if (this.pubSubTargets[queueKey]) {
const targets = this.pubSubTargets[queueKey];
if (!targets.includes(groupId)) {
targets.push(groupId);
this.logger.debug(`Added group [${groupId}] to cache for queue [${queueKey}].`);
}
}
};
this.onConsumerGroupDeleted = (queue, groupId) => {
const queueKey = this.getQueueKey(queue);
this.logger.debug(`Handling 'consumerGroupDeleted' event for group [${groupId}] on queue [${queueKey}]`);
if (this.pubSubTargets[queueKey]) {
const targets = this.pubSubTargets[queueKey];
const index = targets.indexOf(groupId);
if (index > -1) {
targets.splice(index, 1);
this.logger.debug(`Removed group [${groupId}] from cache for queue [${queueKey}].`);
}
}
};
this.onQueueCreated = (queue, properties) => {
var _a;
const queueKey = this.getQueueKey(queue);
this.logger.debug(`Handling 'queueCreated' event for queue [${queueKey}] with delivery model [${index_js_1.EQueueDeliveryModel[properties.deliveryModel]}]`);
if (properties.deliveryModel === index_js_1.EQueueDeliveryModel.PUB_SUB) {
this.pubSubTargets[queueKey] = (_a = this.pubSubTargets[queueKey]) !== null && _a !== void 0 ? _a : [];
this.logger.debug(`Added PUB/SUB queue [${queueKey}] to cache.`);
}
};
this.onQueueDeleted = (queue) => {
const queueKey = this.getQueueKey(queue);
this.logger.debug(`Handling 'queueDeleted' event for queue [${queueKey}]`);
if (this.pubSubTargets[queueKey]) {
delete this.pubSubTargets[queueKey];
this.logger.debug(`Removed queue [${queueKey}] from cache.`);
}
};
this.subscribeToEvents = (cb) => {
this.logger.debug('Subscribing to queue and consumer group events...');
this.internalEventBus.on('queue.queueCreated', this.onQueueCreated);
this.internalEventBus.on('queue.queueDeleted', this.onQueueDeleted);
this.internalEventBus.on('queue.consumerGroupCreated', this.onConsumerGroupCreated);
this.internalEventBus.on('queue.consumerGroupDeleted', this.onConsumerGroupDeleted);
this.logger.debug('Successfully subscribed to events.');
cb();
};
this.unsubscribeFromEvents = (cb) => {
this.logger.debug('Unsubscribing from events...');
this.internalEventBus.removeListener('queue.queueCreated', this.onQueueCreated);
this.internalEventBus.removeListener('queue.queueDeleted', this.onQueueDeleted);
this.internalEventBus.removeListener('queue.consumerGroupCreated', this.onConsumerGroupCreated);
this.internalEventBus.removeListener('queue.consumerGroupDeleted', this.onConsumerGroupDeleted);
this.logger.debug('Successfully unsubscribed from all events.');
cb();
};
this.loadAndCacheInitialTargets = (cb) => {
this.logger.debug('Loading and caching initial PUB/SUB targets...');
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((redisClient, cb) => {
redis_smq_common_1.async.waterfall([
(cb) => {
(0, _get_queues_js_1._getQueues)(redisClient, cb);
},
(queues, cb) => {
this.logger.debug(`Found [${queues.length}] queues to process.`);
redis_smq_common_1.async.eachOf(queues, (queue, index, done) => {
const queueKey = this.getQueueKey(queue);
this.logger.debug(`Processing queue [${queueKey}] (${index + 1}/${queues.length})`);
redis_smq_common_1.async.waterfall([
(cb) => {
(0, _get_queue_properties_js_1._getQueueProperties)(redisClient, queue, cb);
},
(properties, cb) => {
if (properties.deliveryModel === index_js_1.EQueueDeliveryModel.PUB_SUB) {
(0, _get_consumer_groups_js_1._getConsumerGroups)(redisClient, queue, (err, reply) => {
if (err)
return cb(err);
const targets = reply !== null && reply !== void 0 ? reply : [];
this.pubSubTargets[queueKey] = targets;
this.logger.debug(`Cached [${targets.length}] targets for PUB/SUB queue [${queueKey}].`);
cb();
});
}
else {
cb();
}
},
], (err) => {
if (err) {
this.logger.error(`Error processing queue [${queueKey}]. Skipping.`, err);
}
done();
});
}, () => {
this.logger.debug('Finished initial loading of PUB/SUB targets.');
cb();
});
},
], (err) => {
if (err) {
this.logger.error('Failed to complete initial target loading.', err);
}
else {
this.logger.debug('Initial target cache is ready.');
}
cb(err);
});
}, cb);
};
this.clearCache = (cb) => {
this.logger.debug('Clearing PUB/SUB target cache...');
const count = Object.keys(this.pubSubTargets).length;
this.pubSubTargets = {};
this.logger.debug(`Cleared [${count}] entries from cache.`);
cb();
};
this.producerId = producer.getId();
this.logger = logger.createLogger(this.constructor.name);
this.internalEventBus = internal_event_bus_js_1.InternalEventBus.getInstance();
this.logger.debug(`PubSubTargetResolver instance created for producer ${this.producerId}`);
}
getQueueKey(queue) {
return `${queue.name}@${queue.ns}`;
}
goingUp() {
return super
.goingUp()
.concat([this.subscribeToEvents, this.loadAndCacheInitialTargets]);
}
goingDown() {
return [this.unsubscribeFromEvents, this.clearCache].concat(super.goingDown());
}
resolveTargets(queue) {
const queueKey = this.getQueueKey(queue);
this.logger.debug(`Resolving targets for queue [${queueKey}]`);
if (this.pubSubTargets[queueKey]) {
const targets = this.pubSubTargets[queueKey];
this.logger.debug(`Found queue [${queueKey}] in cache with [${targets.length}] targets.`);
return {
isPubSub: true,
targets,
};
}
this.logger.debug(`Queue [${queueKey}] not found in cache.`);
return {
isPubSub: false,
targets: [],
};
}
}
exports.PubSubTargetResolver = PubSubTargetResolver;
//# sourceMappingURL=pub-sub-target-resolver.js.map