UNPKG

redis-smq

Version:

A high-performance, reliable, and scalable message queue for Node.js.

240 lines 15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExchangeFanout = void 0; const redis_smq_common_1 = require("redis-smq-common"); const with_shared_pool_connection_js_1 = require("../../common/redis/redis-connection-pool/with-shared-pool-connection.js"); const redis_keys_js_1 = require("../../common/redis/redis-keys/redis-keys.js"); const configuration_js_1 = require("../../config-manager/configuration.js"); const index_js_1 = require("../../errors/index.js"); const _parse_queue_params_js_1 = require("../../queue-manager/_/_parse-queue-params.js"); const index_js_2 = require("../../queue-manager/index.js"); const _parse_exchange_params_js_1 = require("../_/_parse-exchange-params.js"); const _save_exchange_js_1 = require("../_/_save-exchange.js"); const _validate_queue_binding_js_1 = require("../_/_validate-queue-binding.js"); const _validate_exchange_js_1 = require("../_/_validate-exchange.js"); const index_js_3 = require("../types/index.js"); const _get_bound_queues_js_1 = require("./_/_get-bound-queues.js"); const _validate_operation_js_1 = require("../../queue-operation-validator/_/_validate-operation.js"); const index_js_4 = require("../../queue-operation-validator/index.js"); class ExchangeFanout { constructor() { this.type = index_js_3.EExchangeType.FANOUT; this.logger = (0, redis_smq_common_1.createLogger)(configuration_js_1.Configuration.getConfig().logger, this.constructor.name); } matchQueues(exchange, cb) { return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => { this.getBindings(exchange, callback); }); } create(exchange, queuePolicy, cb) { return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => { const exchangeParams = (0, _parse_exchange_params_js_1._parseExchangeParams)(exchange, this.type); if (exchangeParams instanceof Error) return callback(new index_js_1.InvalidFanoutExchangeParametersError()); (0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => (0, _save_exchange_js_1._saveExchange)(client, exchangeParams, queuePolicy, cb), callback); }); } delete(exchange, cb) { return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => { const exchangeParams = (0, _parse_exchange_params_js_1._parseExchangeParams)(exchange, this.type); if (exchangeParams instanceof Error) return callback(exchangeParams); const { keyExchanges } = redis_keys_js_1.redisKeys.getMainKeys(); const { keyNamespaceExchanges } = redis_keys_js_1.redisKeys.getNamespaceKeys(exchangeParams.ns); const { keyExchange } = redis_keys_js_1.redisKeys.getExchangeKeys(exchangeParams.ns, exchangeParams.name); const { keyFanoutQueues } = redis_keys_js_1.redisKeys.getExchangeFanoutKeys(exchangeParams.ns, exchangeParams.name); const exchangeStr = JSON.stringify(exchangeParams); (0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, outerCb) => { (0, redis_smq_common_1.withWatchTransaction)(client, (c, watch, done) => { let boundQueuesCount = 0; redis_smq_common_1.async.waterfall([ (cb1) => watch([ keyExchange, keyFanoutQueues, keyExchanges, keyNamespaceExchanges, ], cb1), (_, cb1) => (0, _validate_exchange_js_1._validateExchange)(c, exchangeParams, true, cb1), (_, cb1) => c.sscanAll(keyFanoutQueues, {}, (err, queues) => { var _a; if (err) return cb1(err); boundQueuesCount = (_a = queues === null || queues === void 0 ? void 0 : queues.length) !== null && _a !== void 0 ? _a : 0; if (boundQueuesCount > 0) { this.logger.warn(`delete: exchange has ${boundQueuesCount} bound queues, aborting`); return cb1(new index_js_1.ExchangeHasBoundQueuesError()); } cb1(); }), (_, cb1) => { const multi = c.multi(); multi.del(keyExchange); multi.del(keyFanoutQueues); multi.srem(keyExchanges, exchangeStr); multi.srem(keyNamespaceExchanges, exchangeStr); cb1(null, { multi }); }, ], done); }, (err) => { if (err) return outerCb(err); this.logger.info(`delete: deleted exchange ${exchangeParams.name}@${exchangeParams.ns}`); outerCb(); }, { maxAttempts: 5, onRetry: (attemptNo, maxAttempts) => this.logger.warn(`delete: concurrent modification, retrying attempt=${attemptNo}/${maxAttempts}`), }); }, callback); }); } bindQueue(queue, exchange, cb) { return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => { const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue); const exchangeParams = (0, _parse_exchange_params_js_1._parseExchangeParams)(exchange, this.type); if (queueParams instanceof Error) return callback(queueParams); if (exchangeParams instanceof Error) return callback(exchangeParams); if (queueParams.ns !== exchangeParams.ns) { return callback(new index_js_1.NamespaceMismatchError()); } this.logger.info(`bindQueue: bind queue=${queueParams.name}@${queueParams.ns} -> ex=${exchangeParams.name}@${exchangeParams.ns}`); const { keyQueueProperties, keyQueueExchangeBindings } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams.ns, queueParams.name, null); const { keyExchange } = redis_keys_js_1.redisKeys.getExchangeKeys(exchangeParams.ns, exchangeParams.name); const { keyFanoutQueues } = redis_keys_js_1.redisKeys.getExchangeFanoutKeys(exchangeParams.ns, exchangeParams.name); const { keyExchanges } = redis_keys_js_1.redisKeys.getMainKeys(); const { keyNamespaceExchanges } = redis_keys_js_1.redisKeys.getNamespaceKeys(queueParams.ns); const exchangeStr = JSON.stringify(exchangeParams); const queueStr = JSON.stringify(queueParams); (0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, outerCb) => { redis_smq_common_1.async.series([ (cb) => (0, _validate_operation_js_1._validateOperation)(client, queueParams, index_js_4.EQueueOperation.BIND_EXCHANGE, cb), (cb) => (0, redis_smq_common_1.withWatchTransaction)(client, (c, watch, done) => { let exchangeQueuePolicy; redis_smq_common_1.async.waterfall([ (cb1) => watch([ keyExchange, keyQueueProperties, keyFanoutQueues, keyQueueExchangeBindings, keyExchanges, keyNamespaceExchanges, ], cb1), (_, cb1) => (0, _validate_queue_binding_js_1._validateQueueBinding)(c, exchangeParams, queueParams, (err, reply) => { if (err) return cb1(err); if (!reply) return cb1(new redis_smq_common_1.CallbackEmptyReplyError()); const [queueProperties] = reply; exchangeQueuePolicy = queueProperties.queueType === index_js_2.EQueueType.PRIORITY_QUEUE ? index_js_3.EExchangeQueuePolicy.PRIORITY : index_js_3.EExchangeQueuePolicy.STANDARD; cb1(); }), (_, cb1) => c.sismember(keyFanoutQueues, queueStr, (err, reply) => { if (err) return cb1(err); if (reply === 1) { this.logger.debug('bindQueue: already bound'); return cb1(new index_js_1.QueueAlreadyBound()); } cb1(); }), (_, cb1) => { const typeField = String(index_js_3.EExchangeProperty.TYPE); const queuePolicyField = String(index_js_3.EExchangeProperty.QUEUE_POLICY); const multi = c.multi(); multi.hset(keyExchange, typeField, index_js_3.EExchangeType.FANOUT); multi.hset(keyExchange, queuePolicyField, exchangeQueuePolicy); multi.sadd(keyExchanges, exchangeStr); multi.sadd(keyNamespaceExchanges, exchangeStr); multi.sadd(keyFanoutQueues, queueStr); multi.sadd(keyQueueExchangeBindings, exchangeStr); cb1(null, { multi }); }, ], done); }, (err) => { if (err) { if (err instanceof index_js_1.QueueAlreadyBound) return cb(); return cb(err); } this.logger.info(`bindQueue: bound queue=${queueParams.name}@${queueParams.ns} -> ex=${exchangeParams.name}@${exchangeParams.ns}`); cb(); }, { maxAttempts: 5, onRetry: (attemptNo, maxAttempts) => this.logger.warn(`bindQueue: concurrent modification, retrying attempt=${attemptNo}/${maxAttempts}`), }), ], (err) => outerCb(err)); }, callback); }); } unbindQueue(queue, exchange, cb) { return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => { const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue); const exchangeParams = (0, _parse_exchange_params_js_1._parseExchangeParams)(exchange, this.type); if (queueParams instanceof Error) return callback(queueParams); if (exchangeParams instanceof Error) return callback(exchangeParams); if (queueParams.ns !== exchangeParams.ns) { this.logger.error(`Namespace mismatch`); return callback(new index_js_1.NamespaceMismatchError()); } const { keyQueueProperties, keyQueueExchangeBindings } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams.ns, queueParams.name, null); const { keyExchange } = redis_keys_js_1.redisKeys.getExchangeKeys(exchangeParams.ns, exchangeParams.name); const { keyFanoutQueues } = redis_keys_js_1.redisKeys.getExchangeFanoutKeys(exchangeParams.ns, exchangeParams.name); const queueStr = JSON.stringify(queueParams); const exchangeStr = JSON.stringify(exchangeParams); (0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, outerCb) => { redis_smq_common_1.async.series([ (cb) => (0, _validate_operation_js_1._validateOperation)(client, queueParams, index_js_4.EQueueOperation.UNBIND_EXCHANGE, cb), (cb) => (0, redis_smq_common_1.withWatchTransaction)(client, (c, watch, done) => { redis_smq_common_1.async.waterfall([ (cb1) => watch([ keyExchange, keyQueueProperties, keyFanoutQueues, keyQueueExchangeBindings, ], cb1), (_, cb1) => (0, _validate_exchange_js_1._validateExchange)(c, exchangeParams, true, cb1), (_, cb1) => c.sismember(keyFanoutQueues, queueStr, (err, reply) => { if (err) return cb1(err); if (reply !== 1) return cb1(new index_js_1.QueueNotBoundError()); cb1(); }), (_, cb1) => { const multi = c.multi(); multi.srem(keyFanoutQueues, queueStr); multi.srem(keyQueueExchangeBindings, exchangeStr); cb1(null, { multi }); }, ], done); }, (err) => { if (err) return cb(err); this.logger.info(`unbindQueue: unbound queue=${queueParams.name}@${queueParams.ns} from ex=${exchangeParams.name}@${exchangeParams.ns}`); cb(); }, { maxAttempts: 5, onRetry: (attemptNo, maxAttempts) => this.logger.warn(`unbindQueue: concurrent modification, retrying attempt=${attemptNo}/${maxAttempts}`), }), ], (err) => outerCb(err)); }, callback); }); } getBindings(exchange, cb) { return redis_smq_common_1.async.withOptionalCallback(cb, (callback) => { const exchangeParams = (0, _parse_exchange_params_js_1._parseExchangeParams)(exchange, this.type); if (exchangeParams instanceof Error) return callback(exchangeParams); (0, with_shared_pool_connection_js_1.withSharedPoolConnection)((client, cb) => (0, _get_bound_queues_js_1._getBoundQueues)(client, exchangeParams, cb), callback); }); } } exports.ExchangeFanout = ExchangeFanout; //# sourceMappingURL=exchange-fanout.js.map