redis-smq
Version:
A high-performance, reliable, and scalable message queue for Node.js.
259 lines • 15.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueueManager = void 0;
const redis_smq_common_1 = require("redis-smq-common");
const scripts_js_1 = require("../common/redis/scripts.js");
const redis_keys_js_1 = require("../common/redis/redis-keys/redis-keys.js");
const configuration_js_1 = require("../config-manager/configuration.js");
const _delete_queue_js_1 = require("./_/_delete-queue.js");
const _get_queue_consumer_ids_js_1 = require("./_/_get-queue-consumer-ids.js");
const _get_queue_consumers_js_1 = require("./_/_get-queue-consumers.js");
const _get_queue_properties_js_1 = require("./_/_get-queue-properties.js");
const _get_queues_js_1 = require("./_/_get-queues.js");
const _parse_queue_params_js_1 = require("./_/_parse-queue-params.js");
const _queue_exists_js_1 = require("./_/_queue-exists.js");
const index_js_1 = require("../errors/index.js");
const index_js_2 = require("./types/index.js");
const with_shared_pool_connection_js_1 = require("../common/redis/redis-connection-pool/with-shared-pool-connection.js");
const event_multiplexer_js_1 = require("../event-bus/event-multiplexer.js");
const _set_queue_state_js_1 = require("../queue-state-manager/_/_set-queue-state.js");
const index_js_3 = require("../queue-state-manager/index.js");
class QueueManager {
constructor() {
const config = configuration_js_1.Configuration.getConfig();
this.logger = (0, redis_smq_common_1.createLogger)(config.logger, this.constructor.name);
}
save(queue, queueType, deliveryModel, cb) {
return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => {
const queueDesc = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`;
this.logger.debug(`Saving queue: ${queueDesc}, type: ${queueType}, delivery model: ${deliveryModel}`);
const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
if (queueParams instanceof Error) {
this.logger.error(`Error parsing queue parameters for ${queueDesc}: ${queueParams.message}`, queueParams);
return callback(queueParams);
}
const queueName = `${queueParams.name}@${queueParams.ns}`;
this.logger.debug(`Parsed queue parameters: ${queueName}`);
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, done) => {
const { keyQueueProperties, keyQueueStateHistory } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams.ns, queueParams.name, null);
const { keyNamespaces, keyQueues } = redis_keys_js_1.redisKeys.getMainKeys();
const { keyNamespaceQueues } = redis_keys_js_1.redisKeys.getNamespaceKeys(queueParams.ns);
const keys = [
keyNamespaces,
keyNamespaceQueues,
keyQueues,
keyQueueProperties,
keyQueueStateHistory,
];
const now = Date.now();
const initialState = {
timestamp: now,
from: null,
to: index_js_2.EQueueOperationalState.ACTIVE,
reason: index_js_3.ESystemStateTransitionReason.SYSTEM_INIT,
metadata: {
queueType,
deliveryModel,
},
};
const initialTransitionData = JSON.stringify(initialState);
const args = [
queueParams.ns,
JSON.stringify(queueParams),
index_js_2.EQueueProperty.QUEUE_TYPE,
queueType,
index_js_2.EQueueProperty.DELIVERY_MODEL,
deliveryModel,
index_js_2.EQueueProperty.RATE_LIMIT,
'',
index_js_2.EQueueProperty.MESSAGES_COUNT,
index_js_2.EQueueProperty.ACKNOWLEDGED_MESSAGES_COUNT,
index_js_2.EQueueProperty.DEAD_LETTERED_MESSAGES_COUNT,
index_js_2.EQueueProperty.PENDING_MESSAGES_COUNT,
index_js_2.EQueueProperty.SCHEDULED_MESSAGES_COUNT,
index_js_2.EQueueProperty.PROCESSING_MESSAGES_COUNT,
index_js_2.EQueueProperty.DELAYED_MESSAGES_COUNT,
index_js_2.EQueueProperty.REQUEUED_MESSAGES_COUNT,
index_js_2.EQueueProperty.OPERATIONAL_STATE,
index_js_2.EQueueOperationalState.ACTIVE,
_set_queue_state_js_1.maxQueueStateHistorySize,
index_js_2.EQueueProperty.LAST_STATE_CHANGE_AT,
now,
index_js_2.EQueueProperty.LOCK_ID,
initialTransitionData,
];
this.logger.debug(`Executing CREATE_QUEUE script for ${queueName} with keys: [${keys.join(', ')}]`);
client.runScript(scripts_js_1.ERedisScriptName.CREATE_QUEUE, keys, args, (err, reply) => {
if (err)
return done(err);
if (!['OK', 'QUEUE_EXISTS'].includes(String(reply))) {
this.logger.error('CREATE_QUEUE script returned an unexpected reply: ', reply);
return done(new index_js_1.UnexpectedScriptReplyError({ metadata: { reply } }));
}
if (reply === 'QUEUE_EXISTS') {
const error = new index_js_1.QueueAlreadyExistsError();
this.logger.error(`Queue ${queueName} already exists`, error);
return done(error);
}
this.logger.debug(`Queue ${queueName} created successfully.`);
const properties = {
queueType,
deliveryModel,
rateLimit: null,
messagesCount: 0,
acknowledgedMessagesCount: 0,
deadLetteredMessagesCount: 0,
pendingMessagesCount: 0,
scheduledMessagesCount: 0,
processingMessagesCount: 0,
delayedMessagesCount: 0,
requeuedMessagesCount: 0,
operationalState: index_js_2.EQueueOperationalState.ACTIVE,
lockId: null,
lastStateChangeAt: now,
};
this.logger.debug(`Emitting queue.queueCreated event for ${queueName}`);
event_multiplexer_js_1.EventMultiplexer.publish('queue.queueCreated', queueParams, properties);
this.logger.info(`Queue ${queueName} successfully created with type=${queueType}, deliveryModel=${deliveryModel}, state=${index_js_2.EQueueOperationalState.ACTIVE}`);
done(null, { queue: queueParams, properties });
});
}, callback);
});
}
exists(queue, cb) {
return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => {
const queueDesc = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`;
this.logger.debug(`Checking if queue exists: ${queueDesc}`);
const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
if (queueParams instanceof Error) {
this.logger.error(`Error parsing queue parameters for ${queueDesc}: ${queueParams.message}`, queueParams);
callback(queueParams);
}
else {
const queueName = `${queueParams.name}@${queueParams.ns}`;
this.logger.debug(`Parsed queue parameters: ${queueName}`);
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => {
this.logger.debug(`Checking if queue ${queueName} exists in Redis`);
(0, _queue_exists_js_1._queueExists)(client, queueParams, (err, exists) => {
if (err) {
this.logger.error(`Error checking if queue ${queueName} exists: ${err.message}`, err);
cb(err);
}
else {
this.logger.debug(`Queue ${queueName} exists: ${exists}`);
cb(null, exists);
}
});
}, callback);
}
});
}
delete(queue, cb) {
return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => {
const queueDesc = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`;
this.logger.debug(`Deleting queue: ${queueDesc}`);
const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
if (queueParams instanceof Error) {
this.logger.error(`Error parsing queue parameters for ${queueDesc}: ${queueParams.message}`, queueParams);
return callback(queueParams);
}
const queueName = `${queueParams.name}@${queueParams.ns}`;
this.logger.debug(`Parsed queue parameters: ${queueName}`);
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => {
this.logger.debug(`Executing delete queue operation for ${queueName}`);
(0, _delete_queue_js_1._deleteQueue)(client, queueParams, (err) => {
if (err) {
this.logger.error(`Error deleting queue ${queueName}: ${err.message}`, err);
return cb(err);
}
this.logger.debug(`Queue ${queueName} deleted from Redis, emitting queue.queueDeleted event`);
event_multiplexer_js_1.EventMultiplexer.publish('queue.queueDeleted', queueParams);
this.logger.info(`Queue ${queueParams.name}@${queueParams.ns} successfully deleted`);
cb();
});
}, callback);
});
}
getProperties(queue, cb) {
return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => {
const queueDesc = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`;
this.logger.debug(`Getting properties for queue: ${queueDesc}`);
const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
if (queueParams instanceof Error) {
this.logger.error(`Error parsing queue parameters for ${queueDesc}: ${queueParams.message}`, queueParams);
callback(queueParams);
}
else {
const queueName = `${queueParams.name}@${queueParams.ns}`;
this.logger.debug(`Parsed queue parameters: ${queueName}`);
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => {
this.logger.debug(`Retrieving properties for queue ${queueName}`);
(0, _get_queue_properties_js_1._getQueueProperties)(client, queueParams, (err, properties) => {
if (err) {
this.logger.error(`Error getting properties for queue ${queueName}: ${err.message}`, err);
cb(err);
}
else {
if (properties) {
this.logger.debug(`Retrieved properties for queue ${queueName}: type=${index_js_2.EQueueType[properties.queueType]}, deliveryModel=${index_js_2.EQueueDeliveryModel[properties.deliveryModel]}, state=${properties.operationalState}`);
}
else {
this.logger.debug(`No properties found for queue ${queueName}`);
}
cb(null, properties);
}
});
}, callback);
}
});
}
getQueues(cb) {
return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => {
this.logger.debug('Getting all queues');
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => {
this.logger.debug('Retrieving all queues from Redis');
(0, _get_queues_js_1._getQueues)(client, (err, queues) => {
if (err) {
this.logger.error(`Error getting queues: ${err.message}`, err);
cb(err);
}
else {
const queueCount = (queues === null || queues === void 0 ? void 0 : queues.length) || 0;
this.logger.debug(`Retrieved ${queueCount} queues`);
cb(null, queues);
}
});
}, callback);
});
}
getConsumers(queue, cb) {
return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => {
const queueDesc = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`;
this.logger.debug(`Getting consumers for queue: ${queueDesc}`);
const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
if (queueParams instanceof Error) {
this.logger.error(`Error parsing queue parameters for ${queueDesc}: ${queueParams.message}`, queueParams);
return callback(queueParams);
}
const queueName = `${queueParams.name}@${queueParams.ns}`;
this.logger.debug(`Parsed queue parameters: ${queueName}`);
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => (0, _get_queue_consumers_js_1._getQueueConsumers)(client, queueParams, cb), callback);
});
}
getConsumerIds(queue, cb) {
return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => {
const queueDesc = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`;
this.logger.debug(`Getting consumer Ids for queue: ${queueDesc}`);
const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
if (queueParams instanceof Error) {
this.logger.error(`Error parsing queue parameters for ${queueDesc}: ${queueParams.message}`, queueParams);
return callback(queueParams);
}
const queueName = `${queueParams.name}@${queueParams.ns}`;
this.logger.debug(`Parsed queue parameters: ${queueName}`);
(0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => (0, _get_queue_consumer_ids_js_1._getQueueConsumerIds)(client, queueParams, cb), callback);
});
}
}
exports.QueueManager = QueueManager;
//# sourceMappingURL=queue-manager.js.map