redis-smq
Version:
A simple high-performance Redis message queue for Node.js.
126 lines • 5.63 kB
JavaScript
import { async, CallbackEmptyReplyError, logger, } from 'redis-smq-common';
import { RedisClient } from '../../common/redis-client/redis-client.js';
import { ELuaScriptName } from '../../common/redis-client/scripts/scripts.js';
import { redisKeys } from '../../common/redis-keys/redis-keys.js';
import { Configuration } from '../../config/index.js';
import { _parseQueueParamsAndValidate } from '../queue/_/_parse-queue-params-and-validate.js';
import { EQueueProperty, Queue, } from '../queue/index.js';
import { _hasRateLimitExceeded } from './_/_has-rate-limit-exceeded.js';
import { QueueRateLimitInvalidIntervalError, QueueRateLimitInvalidLimitError, QueueRateLimitQueueNotFoundError, } from './errors/index.js';
export class QueueRateLimit {
redisClient;
logger;
queue;
constructor() {
this.logger = logger.getLogger(Configuration.getSetConfig().logger, `queue-rate-limit`);
this.redisClient = new RedisClient();
this.redisClient.on('error', (err) => this.logger.error(err));
this.queue = new Queue();
}
clear(queue, cb) {
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else
_parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
if (err)
cb(err);
else if (!queueParams)
cb(new CallbackEmptyReplyError());
else {
const { keyQueueProperties, keyQueueRateLimitCounter } = redisKeys.getQueueKeys(queueParams, null);
const multi = client.multi();
multi.hdel(keyQueueProperties, String(EQueueProperty.RATE_LIMIT));
multi.del(keyQueueRateLimitCounter);
multi.exec((err) => cb(err));
}
});
});
}
set(queue, rateLimit, cb) {
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else
_parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
if (err)
cb(err);
else if (!queueParams)
cb(new CallbackEmptyReplyError());
else {
const limit = Number(rateLimit.limit);
if (isNaN(limit) || limit <= 0) {
cb(new QueueRateLimitInvalidLimitError());
}
const interval = Number(rateLimit.interval);
if (isNaN(interval) || interval < 1000) {
cb(new QueueRateLimitInvalidIntervalError());
}
const validatedRateLimit = { interval, limit };
const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
client.runScript(ELuaScriptName.SET_QUEUE_RATE_LIMIT, [keyQueueProperties], [EQueueProperty.RATE_LIMIT, JSON.stringify(validatedRateLimit)], (err, reply) => {
if (err)
cb(err);
else if (reply !== 'OK')
cb(new QueueRateLimitQueueNotFoundError());
else
cb();
});
}
});
});
}
hasExceeded(queue, rateLimit, cb) {
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else
_parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
if (err)
cb(err);
else if (!queueParams)
cb(new CallbackEmptyReplyError());
else
_hasRateLimitExceeded(client, queueParams, rateLimit, cb);
});
});
}
get(queue, cb) {
this.redisClient.getSetInstance((err, client) => {
if (err)
cb(err);
else if (!client)
cb(new CallbackEmptyReplyError());
else
_parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
if (err)
cb(err);
else if (!queueParams)
cb(new CallbackEmptyReplyError());
else {
const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
client.hget(keyQueueProperties, String(EQueueProperty.RATE_LIMIT), (err, reply) => {
if (err)
cb(err);
else if (!reply)
cb(null, null);
else {
const rateLimit = JSON.parse(reply);
cb(null, rateLimit);
}
});
}
});
});
}
shutdown = (cb) => {
async.waterfall([this.queue.shutdown, this.redisClient.shutdown], cb);
};
}
//# sourceMappingURL=queue-rate-limit.js.map