redis-smq
Version:
A high-performance, reliable, and scalable message queue for Node.js.
157 lines • 7.33 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DequeueMessage = void 0;
const redis_smq_common_1 = require("redis-smq-common");
const redis_keys_js_1 = require("../../../common/redis/redis-keys/redis-keys.js");
const _has_rate_limit_exceeded_js_1 = require("../../../queue-rate-limit/_/_has-rate-limit-exceeded.js");
const _get_queue_properties_js_1 = require("../../../queue-manager/_/_get-queue-properties.js");
const index_js_1 = require("../../../index.js");
const event_publisher_js_1 = require("./event-publisher.js");
const connection_pool_js_1 = require("../../../common/redis/redis-connection-pool/types/connection-pool.js");
const redis_connection_pool_js_1 = require("../../../common/redis/redis-connection-pool/redis-connection-pool.js");
class DequeueMessage extends redis_smq_common_1.Runnable {
constructor(consumerContext, queue, blockUntilMessageReceived = true, autoCloseRedisConnection = true) {
super();
this.redisClient = null;
this.queueRateLimit = null;
this.queueType = null;
this.handleMessage = (err, messageId) => {
if (err) {
this.handleError(err);
}
else if (typeof messageId === 'string') {
this.emit('consumer.dequeueMessage.messageReceived', messageId, this.queue, this.consumerContext.consumerId);
}
else {
this.emit('consumer.dequeueMessage.nextMessage');
}
};
this.consumerContext = consumerContext;
this.logger = consumerContext.logger.createLogger(this.constructor.name);
this.config = consumerContext.config;
this.queue = queue;
this.blockUntilMessageReceived = blockUntilMessageReceived;
this.autoCloseRedisConnection = autoCloseRedisConnection;
(0, event_publisher_js_1.eventPublisher)(this);
const { keyConsumerQueues } = redis_keys_js_1.redisKeys.getConsumerKeys(this.consumerContext.consumerId);
const { keyQueueProcessing } = redis_keys_js_1.redisKeys.getQueueConsumerKeys(this.queue.queueParams, this.consumerContext.consumerId);
const { keyQueues } = redis_keys_js_1.redisKeys.getMainKeys();
const { keyQueueProcessingQueues, keyQueuePending, keyQueuePriority, keyQueueConsumers, keyQueueProperties, } = redis_keys_js_1.redisKeys.getQueueKeys(this.queue.queueParams.ns, this.queue.queueParams.name, this.queue.groupId);
this.keyQueueProperties = keyQueueProperties;
this.keyQueuePriorityPending = keyQueuePriority;
this.keyQueuePending = keyQueuePending;
this.keyQueueProcessing = keyQueueProcessing;
this.keyQueues = keyQueues;
this.keyQueueConsumers = keyQueueConsumers;
this.keyConsumerQueues = keyConsumerQueues;
this.keyQueueProcessingQueues = keyQueueProcessingQueues;
}
runDequeue(redisClient) {
if (this.queueRateLimit) {
(0, _has_rate_limit_exceeded_js_1._hasRateLimitExceeded)(redisClient, this.queue.queueParams, this.queueRateLimit, (err, isExceeded) => {
if (err)
this.handleError(err);
else if (isExceeded) {
this.emit('consumer.dequeueMessage.nextMessage');
}
else {
this.performDequeue(redisClient);
}
});
}
else {
this.performDequeue(redisClient);
}
}
performDequeue(redisClient) {
if (this.isPriorityQueuingEnabled()) {
redisClient.zpoplpush(this.keyQueuePriorityPending, this.keyQueueProcessing, this.handleMessage);
}
else if (this.blockUntilMessageReceived && !this.queueRateLimit) {
redisClient.brpoplpush(this.keyQueuePending, this.keyQueueProcessing, 0, this.handleMessage);
}
else {
redisClient.rpoplpush(this.keyQueuePending, this.keyQueueProcessing, this.handleMessage);
}
}
getRedisClient() {
if (!this.redisClient)
return new redis_smq_common_1.PanicError({ message: 'A RedisClient instance is required.' });
return this.redisClient;
}
handleError(err) {
if (!this.isOperational())
return;
this.logger.error(`DequeueMessage error: ${err.message}`, err);
this.emit('consumer.dequeueMessage.error', err, this.consumerContext.consumerId, this.queue);
super.handleError(err);
}
goingUp() {
return super.goingUp().concat([
(cb) => {
const redisConnectionAcquisitionMode = this.blockUntilMessageReceived
? connection_pool_js_1.ERedisConnectionAcquisitionMode.EXCLUSIVE
: connection_pool_js_1.ERedisConnectionAcquisitionMode.SHARED;
redis_connection_pool_js_1.RedisConnectionPool.getInstance().acquire(redisConnectionAcquisitionMode, (err, redisClient) => {
if (err)
return cb(err);
if (!redisClient)
return cb(new redis_smq_common_1.CallbackEmptyReplyError());
this.redisClient = redisClient;
cb();
});
},
(cb) => {
const redisClient = this.getRedisClient();
if (redisClient instanceof Error)
return cb(redisClient);
(0, _get_queue_properties_js_1._getQueueProperties)(redisClient, this.queue.queueParams, (err, queueProperties) => {
var _a;
if (err)
return cb(err);
if (!queueProperties)
return cb(new redis_smq_common_1.CallbackEmptyReplyError());
this.queueType = queueProperties.queueType;
this.queueRateLimit = (_a = queueProperties.rateLimit) !== null && _a !== void 0 ? _a : null;
cb();
});
},
]);
}
goingDown() {
return [
(cb) => {
if (this.redisClient) {
if (this.autoCloseRedisConnection) {
redis_connection_pool_js_1.RedisConnectionPool.getInstance().destroy(this.redisClient, () => {
this.redisClient = null;
cb();
});
}
else {
redis_connection_pool_js_1.RedisConnectionPool.getInstance().release(this.redisClient);
this.redisClient = null;
cb();
}
}
else
cb();
},
].concat(super.goingDown());
}
isPriorityQueuingEnabled() {
return this.queueType === index_js_1.EQueueType.PRIORITY_QUEUE;
}
dequeue() {
if (!this.isOperational()) {
return;
}
const redisClient = this.getRedisClient();
if (redisClient instanceof Error) {
return this.handleError(redisClient);
}
this.runDequeue(redisClient);
}
}
exports.DequeueMessage = DequeueMessage;
//# sourceMappingURL=dequeue-message.js.map