UNPKG

redis-smq

Version:

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

150 lines 9.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QueueRateLimit = 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 _parse_queue_params_and_validate_js_1 = require("../queue/_/_parse-queue-params-and-validate.js"); const index_js_2 = require("../queue/index.js"); const _has_rate_limit_exceeded_js_1 = require("./_/_has-rate-limit-exceeded.js"); const index_js_3 = require("./errors/index.js"); class QueueRateLimit { constructor() { this.shutdown = (cb) => { this.logger.debug('Shutting down QueueRateLimit'); redis_smq_common_1.async.series([this.queue.shutdown, this.redisClient.shutdown], (err) => { if (err) { this.logger.error(`Error during shutdown: ${err.message}`); return cb(err); } this.logger.info('QueueRateLimit shutdown completed successfully'); cb(); }); }; this.logger = redis_smq_common_1.logger.getLogger(index_js_1.Configuration.getSetConfig().logger, this.constructor.name.toLowerCase()); this.logger.debug('Initializing QueueRateLimit'); this.redisClient = new redis_client_js_1.RedisClient(); this.redisClient.on('error', (err) => this.logger.error(err)); this.queue = new index_js_2.Queue(); this.logger.debug('QueueRateLimit initialized'); } clear(queue, cb) { const queueName = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`; this.logger.debug(`Clearing rate limit for queue: ${queueName}`); (0, redis_smq_common_1.withRedisClient)(this.redisClient, (client, cb) => { this.logger.debug(`Validating queue parameters for: ${queueName}`); redis_smq_common_1.async.withCallback((cb) => (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, cb), (queueParams, cb) => { const { keyQueueProperties, keyQueueRateLimitCounter } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null); this.logger.debug(`Clearing rate limit for queue ${queueParams.name}@${queueParams.ns} using keys: ${keyQueueProperties}, ${keyQueueRateLimitCounter}`); const multi = client.multi(); multi.hdel(keyQueueProperties, String(index_js_2.EQueueProperty.RATE_LIMIT)); multi.del(keyQueueRateLimitCounter); multi.exec((err) => { if (err) { this.logger.error(`Failed to clear rate limit: ${err.message}`); return cb(err); } this.logger.info(`Successfully cleared rate limit for queue: ${queueParams.name}@${queueParams.ns}`); cb(); }); }, cb); }, cb); } set(queue, rateLimit, cb) { const queueName = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`; this.logger.debug(`Setting rate limit for queue: ${queueName}, limit: ${rateLimit.limit}, interval: ${rateLimit.interval}ms`); (0, redis_smq_common_1.withRedisClient)(this.redisClient, (client, cb) => { this.logger.debug(`Validating queue parameters for: ${queueName}`); (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, (err, queueParams) => { if (err) { this.logger.error(`Failed to validate queue parameters: ${err.message}`); return cb(err); } if (!queueParams) { this.logger.error('Queue parameters validation returned empty result'); return cb(new redis_smq_common_1.CallbackEmptyReplyError()); } const limit = Number(rateLimit.limit); if (isNaN(limit) || limit <= 0) { this.logger.error(`Invalid rate limit value: ${rateLimit.limit}`); return cb(new index_js_3.QueueRateLimitInvalidLimitError()); } const interval = Number(rateLimit.interval); if (isNaN(interval) || interval < 1000) { this.logger.error(`Invalid rate limit interval: ${rateLimit.interval}`); return cb(new index_js_3.QueueRateLimitInvalidIntervalError()); } const validatedRateLimit = { interval, limit }; this.logger.debug(`Validated rate limit: ${limit} messages per ${interval}ms for queue: ${queueParams.name}@${queueParams.ns}`); const { keyQueueProperties } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null); this.logger.debug(`Setting rate limit using key: ${keyQueueProperties}`); client.runScript(scripts_js_1.ELuaScriptName.SET_QUEUE_RATE_LIMIT, [keyQueueProperties], [index_js_2.EQueueProperty.RATE_LIMIT, JSON.stringify(validatedRateLimit)], (err, reply) => { if (err) { this.logger.error(`Failed to set rate limit: ${err.message}`); return cb(err); } if (reply !== 'OK') { this.logger.error(`Queue not found when setting rate limit: ${queueParams.name}@${queueParams.ns}`); return cb(new index_js_3.QueueRateLimitQueueNotFoundError()); } this.logger.info(`Successfully set rate limit for queue: ${queueParams.name}@${queueParams.ns}, limit: ${limit}, interval: ${interval}ms`); cb(); }); }); }, cb); } hasExceeded(queue, rateLimit, cb) { const queueName = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`; this.logger.debug(`Checking if rate limit exceeded for queue: ${queueName}, limit: ${rateLimit.limit}, interval: ${rateLimit.interval}ms`); (0, redis_smq_common_1.withRedisClient)(this.redisClient, (client, cb) => { this.logger.debug(`Validating queue parameters for: ${queueName}`); (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, (err, queueParams) => { if (err) { this.logger.error(`Failed to validate queue parameters: ${err.message}`); return cb(err); } if (!queueParams) { this.logger.error('Queue parameters validation returned empty result'); return cb(new redis_smq_common_1.CallbackEmptyReplyError()); } this.logger.debug(`Checking rate limit for queue: ${queueParams.name}@${queueParams.ns}`); (0, _has_rate_limit_exceeded_js_1._hasRateLimitExceeded)(client, queueParams, rateLimit, (err, hasExceeded) => { if (err) { this.logger.error(`Failed to check rate limit: ${err.message}`); return cb(err); } this.logger.debug(`Rate limit check result for queue ${queueParams.name}@${queueParams.ns}: ${hasExceeded ? 'exceeded' : 'not exceeded'}`); cb(null, hasExceeded); }); }); }, cb); } get(queue, cb) { const queueName = typeof queue === 'string' ? queue : `${queue.name}@${queue.ns}`; this.logger.debug(`Getting rate limit for queue: ${queueName}`); (0, redis_smq_common_1.withRedisClient)(this.redisClient, (client, cb) => { this.logger.debug(`Validating queue parameters for: ${queueName}`); redis_smq_common_1.async.withCallback((cb) => (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, cb), (queueParams, cb) => { const { keyQueueProperties } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null); this.logger.debug(`Getting rate limit using key: ${keyQueueProperties}`); client.hget(keyQueueProperties, String(index_js_2.EQueueProperty.RATE_LIMIT), (err, reply) => { if (err) { this.logger.error(`Failed to get rate limit: ${err.message}`); return cb(err); } if (!reply) { this.logger.debug(`No rate limit found for queue: ${queueParams.name}@${queueParams.ns}`); return cb(null, null); } const rateLimit = JSON.parse(reply); this.logger.debug(`Retrieved rate limit for queue ${queueParams.name}@${queueParams.ns}: limit: ${rateLimit.limit}, interval: ${rateLimit.interval}ms`); cb(null, rateLimit); }); }, cb); }, cb); } } exports.QueueRateLimit = QueueRateLimit; //# sourceMappingURL=queue-rate-limit.js.map