redis-smq 8.0.0-rc.23 → 8.0.0-rc.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cjs/src/common/redis-client/scripts/lua/set-queue-rate-limit.lua +14 -0
  3. package/dist/cjs/src/common/redis-client/scripts/scripts.d.ts +2 -1
  4. package/dist/cjs/src/common/redis-client/scripts/scripts.js +4 -0
  5. package/dist/cjs/src/lib/namespace/errors/index.d.ts +1 -0
  6. package/dist/cjs/src/lib/namespace/errors/index.js +3 -1
  7. package/dist/cjs/src/lib/namespace/errors/namespace-invalid-namespace.error.d.ts +4 -0
  8. package/dist/cjs/src/lib/namespace/errors/namespace-invalid-namespace.error.js +8 -0
  9. package/dist/cjs/src/lib/namespace/namespace.js +2 -2
  10. package/dist/cjs/src/lib/queue/_/_parse-queue-extended-params.js +2 -2
  11. package/dist/cjs/src/lib/queue/_/_parse-queue-params-and-validate.d.ts +4 -0
  12. package/dist/cjs/src/lib/queue/_/_parse-queue-params-and-validate.js +22 -0
  13. package/dist/cjs/src/lib/queue/_/_queue-exists.d.ts +4 -0
  14. package/dist/cjs/src/lib/queue/_/_queue-exists.js +15 -0
  15. package/dist/cjs/src/lib/queue/queue.js +3 -9
  16. package/dist/cjs/src/lib/queue-rate-limit/errors/index.d.ts +1 -0
  17. package/dist/cjs/src/lib/queue-rate-limit/errors/index.js +3 -1
  18. package/dist/cjs/src/lib/queue-rate-limit/errors/queue-rate-limit-queue-not-found.error.d.ts +4 -0
  19. package/dist/cjs/src/lib/queue-rate-limit/errors/queue-rate-limit-queue-not-found.error.js +8 -0
  20. package/dist/cjs/src/lib/queue-rate-limit/queue-rate-limit.js +95 -79
  21. package/dist/esm/src/common/redis-client/scripts/lua/set-queue-rate-limit.lua +14 -0
  22. package/dist/esm/src/common/redis-client/scripts/scripts.d.ts +2 -1
  23. package/dist/esm/src/common/redis-client/scripts/scripts.js +4 -0
  24. package/dist/esm/src/lib/namespace/errors/index.d.ts +1 -0
  25. package/dist/esm/src/lib/namespace/errors/index.js +1 -0
  26. package/dist/esm/src/lib/namespace/errors/namespace-invalid-namespace.error.d.ts +4 -0
  27. package/dist/esm/src/lib/namespace/errors/namespace-invalid-namespace.error.js +4 -0
  28. package/dist/esm/src/lib/namespace/namespace.js +3 -3
  29. package/dist/esm/src/lib/queue/_/_parse-queue-extended-params.js +2 -2
  30. package/dist/esm/src/lib/queue/_/_parse-queue-params-and-validate.d.ts +4 -0
  31. package/dist/esm/src/lib/queue/_/_parse-queue-params-and-validate.js +18 -0
  32. package/dist/esm/src/lib/queue/_/_queue-exists.d.ts +4 -0
  33. package/dist/esm/src/lib/queue/_/_queue-exists.js +11 -0
  34. package/dist/esm/src/lib/queue/queue.js +3 -9
  35. package/dist/esm/src/lib/queue-rate-limit/errors/index.d.ts +1 -0
  36. package/dist/esm/src/lib/queue-rate-limit/errors/index.js +1 -0
  37. package/dist/esm/src/lib/queue-rate-limit/errors/queue-rate-limit-queue-not-found.error.d.ts +4 -0
  38. package/dist/esm/src/lib/queue-rate-limit/errors/queue-rate-limit-queue-not-found.error.js +4 -0
  39. package/dist/esm/src/lib/queue-rate-limit/queue-rate-limit.js +96 -80
  40. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
 
2
2
 
3
+ ## [8.0.0-rc.24](https://github.com/weyoss/redis-smq/compare/v8.0.0-rc.23...v8.0.0-rc.24) (2024-05-15)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **namespace:** replace generic error in getNamespaceQueues() ([aa9c8e5](https://github.com/weyoss/redis-smq/commit/aa9c8e5a125bdf1fc8e200263618693671219882))
9
+ * **queue-rate-limit:** always validate queue existence ([538cf78](https://github.com/weyoss/redis-smq/commit/538cf786b3b3131f137d1488d6d130323acb571d))
10
+
11
+
12
+ ### Documentation
13
+
14
+ * add new error classes reference ([6c39625](https://github.com/weyoss/redis-smq/commit/6c3962589537a83fe345e349743a798e73e751a6))
15
+
16
+
17
+ ### Codebase Refactoring
18
+
19
+ * **queue-rate-limit:** move QueueRateLimit.set() logic to LUA ([d104a9c](https://github.com/weyoss/redis-smq/commit/d104a9c038ea321e5e18049bffefc54850d4294f))
20
+ * **queue:** return the original error instance ([14228ec](https://github.com/weyoss/redis-smq/commit/14228ec255776cabf2a9202078cd016f80b5f5da))
21
+
3
22
  ## [8.0.0-rc.23](https://github.com/weyoss/redis-smq/compare/v8.0.0-rc.22...v8.0.0-rc.23) (2024-05-10)
4
23
 
5
24
 
@@ -0,0 +1,14 @@
1
+ local keyQueueProperties = KEYS[1]
2
+
3
+ ---
4
+
5
+ local EQueuePropertyRateLimit = ARGV[1]
6
+ local rateLimit = ARGV[2]
7
+
8
+ local result = redis.call("EXISTS", keyQueueProperties)
9
+ if result == 0 then
10
+ return 'QUEUE_NOT_FOUND';
11
+ end
12
+
13
+ redis.call("HSET", keyQueueProperties, EQueuePropertyRateLimit, rateLimit)
14
+ return 'OK'
@@ -11,6 +11,7 @@ export declare enum ELuaScriptName {
11
11
  DELETE_MESSAGE = "DELETE_MESSAGE",
12
12
  FETCH_MESSAGE_FOR_PROCESSING = "FETCH_MESSAGE_FOR_PROCESSING",
13
13
  DELETE_CONSUMER_GROUP = "DELETE_CONSUMER_GROUP",
14
- CLEANUP_OFFLINE_CONSUMER = "CLEANUP_OFFLINE_CONSUMER"
14
+ CLEANUP_OFFLINE_CONSUMER = "CLEANUP_OFFLINE_CONSUMER",
15
+ SET_QUEUE_RATE_LIMIT = "SET_QUEUE_RATE_LIMIT"
15
16
  }
16
17
  //# sourceMappingURL=scripts.d.ts.map
@@ -42,6 +42,7 @@ var ELuaScriptName;
42
42
  ELuaScriptName["FETCH_MESSAGE_FOR_PROCESSING"] = "FETCH_MESSAGE_FOR_PROCESSING";
43
43
  ELuaScriptName["DELETE_CONSUMER_GROUP"] = "DELETE_CONSUMER_GROUP";
44
44
  ELuaScriptName["CLEANUP_OFFLINE_CONSUMER"] = "CLEANUP_OFFLINE_CONSUMER";
45
+ ELuaScriptName["SET_QUEUE_RATE_LIMIT"] = "SET_QUEUE_RATE_LIMIT";
45
46
  })(ELuaScriptName = exports.ELuaScriptName || (exports.ELuaScriptName = {}));
46
47
  redis_smq_common_1.RedisClientAbstract.addScript(ELuaScriptName.PUBLISH_SCHEDULED_MESSAGE, fs
47
48
  .readFileSync((0, path_1.resolve)((0, redis_smq_common_1.getDirname)(), './lua/publish-scheduled-message.lua'))
@@ -78,4 +79,7 @@ redis_smq_common_1.RedisClientAbstract.addScript(ELuaScriptName.DELETE_CONSUMER_
78
79
  redis_smq_common_1.RedisClientAbstract.addScript(ELuaScriptName.CLEANUP_OFFLINE_CONSUMER, fs
79
80
  .readFileSync((0, path_1.resolve)((0, redis_smq_common_1.getDirname)(), './lua/cleanup-offline-consumer.lua'))
80
81
  .toString());
82
+ redis_smq_common_1.RedisClientAbstract.addScript(ELuaScriptName.SET_QUEUE_RATE_LIMIT, fs
83
+ .readFileSync((0, path_1.resolve)((0, redis_smq_common_1.getDirname)(), './lua/set-queue-rate-limit.lua'))
84
+ .toString());
81
85
  //# sourceMappingURL=scripts.js.map
@@ -1,3 +1,4 @@
1
1
  export { NamespaceNotFoundError } from './namespace-not-found.error.js';
2
2
  export { NamespaceError } from './namespace.error.js';
3
+ export { NamespaceInvalidNamespaceError } from './namespace-invalid-namespace.error.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NamespaceError = exports.NamespaceNotFoundError = void 0;
3
+ exports.NamespaceInvalidNamespaceError = exports.NamespaceError = exports.NamespaceNotFoundError = void 0;
4
4
  var namespace_not_found_error_js_1 = require("./namespace-not-found.error.js");
5
5
  Object.defineProperty(exports, "NamespaceNotFoundError", { enumerable: true, get: function () { return namespace_not_found_error_js_1.NamespaceNotFoundError; } });
6
6
  var namespace_error_js_1 = require("./namespace.error.js");
7
7
  Object.defineProperty(exports, "NamespaceError", { enumerable: true, get: function () { return namespace_error_js_1.NamespaceError; } });
8
+ var namespace_invalid_namespace_error_js_1 = require("./namespace-invalid-namespace.error.js");
9
+ Object.defineProperty(exports, "NamespaceInvalidNamespaceError", { enumerable: true, get: function () { return namespace_invalid_namespace_error_js_1.NamespaceInvalidNamespaceError; } });
8
10
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,4 @@
1
+ import { NamespaceError } from './namespace.error.js';
2
+ export declare class NamespaceInvalidNamespaceError extends NamespaceError {
3
+ }
4
+ //# sourceMappingURL=namespace-invalid-namespace.error.d.ts.map
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NamespaceInvalidNamespaceError = void 0;
4
+ const namespace_error_js_1 = require("./namespace.error.js");
5
+ class NamespaceInvalidNamespaceError extends namespace_error_js_1.NamespaceError {
6
+ }
7
+ exports.NamespaceInvalidNamespaceError = NamespaceInvalidNamespaceError;
8
+ //# sourceMappingURL=namespace-invalid-namespace.error.js.map
@@ -39,7 +39,7 @@ class Namespace {
39
39
  getNamespaceQueues(namespace, cb) {
40
40
  const ns = redis_keys_js_1.redisKeys.validateRedisKey(namespace);
41
41
  if (ns instanceof Error)
42
- cb(ns);
42
+ cb(new index_js_2.NamespaceInvalidNamespaceError());
43
43
  else {
44
44
  this.redisClient.getSetInstance((err, client) => {
45
45
  if (err)
@@ -80,7 +80,7 @@ class Namespace {
80
80
  delete(namespace, cb) {
81
81
  const ns = redis_keys_js_1.redisKeys.validateRedisKey(namespace);
82
82
  if (ns instanceof Error)
83
- cb(ns);
83
+ cb(new index_js_2.NamespaceInvalidNamespaceError());
84
84
  else {
85
85
  this.redisClient.getSetInstance((err, client) => {
86
86
  if (err)
@@ -14,7 +14,7 @@ function _parseQueueExtendedParams(args) {
14
14
  if (typeof args === 'string') {
15
15
  const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(args);
16
16
  if (queueParams instanceof Error)
17
- return new queue_invalid_queue_parameter_error_js_1.QueueInvalidQueueParameterError();
17
+ return queueParams;
18
18
  return {
19
19
  queueParams,
20
20
  groupId: null,
@@ -23,7 +23,7 @@ function _parseQueueExtendedParams(args) {
23
23
  if (isQueueParams(args)) {
24
24
  const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(args);
25
25
  if (queueParams instanceof Error)
26
- return new queue_invalid_queue_parameter_error_js_1.QueueInvalidQueueParameterError();
26
+ return queueParams;
27
27
  return {
28
28
  queueParams,
29
29
  groupId: null,
@@ -0,0 +1,4 @@
1
+ import { ICallback, IRedisClient } from 'redis-smq-common';
2
+ import { IQueueParams } from '../types/queue.js';
3
+ export declare function _parseQueueParamsAndValidate(redisClient: IRedisClient, queue: string | IQueueParams, cb: ICallback<IQueueParams>): void;
4
+ //# sourceMappingURL=_parse-queue-params-and-validate.d.ts.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._parseQueueParamsAndValidate = void 0;
4
+ const queue_queue_not_found_error_js_1 = require("../errors/queue-queue-not-found.error.js");
5
+ const _parse_queue_params_js_1 = require("./_parse-queue-params.js");
6
+ const _queue_exists_js_1 = require("./_queue-exists.js");
7
+ function _parseQueueParamsAndValidate(redisClient, queue, cb) {
8
+ const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
9
+ if (queueParams instanceof Error)
10
+ cb(queueParams);
11
+ else
12
+ (0, _queue_exists_js_1._queueExists)(redisClient, queueParams, (err, reply) => {
13
+ if (err)
14
+ cb(err);
15
+ else if (!reply)
16
+ cb(new queue_queue_not_found_error_js_1.QueueQueueNotFoundError());
17
+ else
18
+ cb(null, queueParams);
19
+ });
20
+ }
21
+ exports._parseQueueParamsAndValidate = _parseQueueParamsAndValidate;
22
+ //# sourceMappingURL=_parse-queue-params-and-validate.js.map
@@ -0,0 +1,4 @@
1
+ import { ICallback, IRedisClient } from 'redis-smq-common';
2
+ import { IQueueParams } from '../types/queue.js';
3
+ export declare function _queueExists(redisClient: IRedisClient, queue: IQueueParams, cb: ICallback<boolean>): void;
4
+ //# sourceMappingURL=_queue-exists.d.ts.map
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._queueExists = void 0;
4
+ const redis_keys_js_1 = require("../../../common/redis-keys/redis-keys.js");
5
+ function _queueExists(redisClient, queue, cb) {
6
+ const { keyQueues } = redis_keys_js_1.redisKeys.getMainKeys();
7
+ redisClient.sismember(keyQueues, JSON.stringify(queue), (err, reply) => {
8
+ if (err)
9
+ cb(err);
10
+ else
11
+ cb(null, !!reply);
12
+ });
13
+ }
14
+ exports._queueExists = _queueExists;
15
+ //# sourceMappingURL=_queue-exists.js.map
@@ -11,6 +11,7 @@ const _delete_queue_js_1 = require("./_/_delete-queue.js");
11
11
  const _get_queue_properties_js_1 = require("./_/_get-queue-properties.js");
12
12
  const _get_queues_js_1 = require("./_/_get-queues.js");
13
13
  const _parse_queue_params_js_1 = require("./_/_parse-queue-params.js");
14
+ const _queue_exists_js_1 = require("./_/_queue-exists.js");
14
15
  const index_js_3 = require("./errors/index.js");
15
16
  const index_js_4 = require("./types/index.js");
16
17
  class Queue {
@@ -85,15 +86,8 @@ class Queue {
85
86
  cb(err);
86
87
  else if (!client)
87
88
  cb(new redis_smq_common_1.CallbackEmptyReplyError());
88
- else {
89
- const { keyQueues } = redis_keys_js_1.redisKeys.getMainKeys();
90
- client.sismember(keyQueues, JSON.stringify(queueParams), (err, reply) => {
91
- if (err)
92
- cb(err);
93
- else
94
- cb(null, !!reply);
95
- });
96
- }
89
+ else
90
+ (0, _queue_exists_js_1._queueExists)(client, queueParams, cb);
97
91
  });
98
92
  }
99
93
  }
@@ -1,4 +1,5 @@
1
1
  export { QueueRateLimitError } from './queue-rate-limit.error.js';
2
2
  export { QueueRateLimitInvalidIntervalError } from './queue-rate-limit-invalid-interval.error.js';
3
3
  export { QueueRateLimitInvalidLimitError } from './queue-rate-limit-invalid-limit.error.js';
4
+ export { QueueRateLimitQueueNotFoundError } from './queue-rate-limit-queue-not-found.error.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueueRateLimitInvalidLimitError = exports.QueueRateLimitInvalidIntervalError = exports.QueueRateLimitError = void 0;
3
+ exports.QueueRateLimitQueueNotFoundError = exports.QueueRateLimitInvalidLimitError = exports.QueueRateLimitInvalidIntervalError = exports.QueueRateLimitError = void 0;
4
4
  var queue_rate_limit_error_js_1 = require("./queue-rate-limit.error.js");
5
5
  Object.defineProperty(exports, "QueueRateLimitError", { enumerable: true, get: function () { return queue_rate_limit_error_js_1.QueueRateLimitError; } });
6
6
  var queue_rate_limit_invalid_interval_error_js_1 = require("./queue-rate-limit-invalid-interval.error.js");
7
7
  Object.defineProperty(exports, "QueueRateLimitInvalidIntervalError", { enumerable: true, get: function () { return queue_rate_limit_invalid_interval_error_js_1.QueueRateLimitInvalidIntervalError; } });
8
8
  var queue_rate_limit_invalid_limit_error_js_1 = require("./queue-rate-limit-invalid-limit.error.js");
9
9
  Object.defineProperty(exports, "QueueRateLimitInvalidLimitError", { enumerable: true, get: function () { return queue_rate_limit_invalid_limit_error_js_1.QueueRateLimitInvalidLimitError; } });
10
+ var queue_rate_limit_queue_not_found_error_js_1 = require("./queue-rate-limit-queue-not-found.error.js");
11
+ Object.defineProperty(exports, "QueueRateLimitQueueNotFoundError", { enumerable: true, get: function () { return queue_rate_limit_queue_not_found_error_js_1.QueueRateLimitQueueNotFoundError; } });
10
12
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,4 @@
1
+ import { QueueRateLimitError } from './queue-rate-limit.error.js';
2
+ export declare class QueueRateLimitQueueNotFoundError extends QueueRateLimitError {
3
+ }
4
+ //# sourceMappingURL=queue-rate-limit-queue-not-found.error.d.ts.map
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueueRateLimitQueueNotFoundError = void 0;
4
+ const queue_rate_limit_error_js_1 = require("./queue-rate-limit.error.js");
5
+ class QueueRateLimitQueueNotFoundError extends queue_rate_limit_error_js_1.QueueRateLimitError {
6
+ }
7
+ exports.QueueRateLimitQueueNotFoundError = QueueRateLimitQueueNotFoundError;
8
+ //# sourceMappingURL=queue-rate-limit-queue-not-found.error.js.map
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.QueueRateLimit = void 0;
4
4
  const redis_smq_common_1 = require("redis-smq-common");
5
5
  const redis_client_instance_js_1 = require("../../common/redis-client/redis-client-instance.js");
6
+ const scripts_js_1 = require("../../common/redis-client/scripts/scripts.js");
6
7
  const redis_keys_js_1 = require("../../common/redis-keys/redis-keys.js");
7
8
  const index_js_1 = require("../../config/index.js");
9
+ const _parse_queue_params_and_validate_js_1 = require("../queue/_/_parse-queue-params-and-validate.js");
8
10
  const index_js_2 = require("../queue/index.js");
9
- const _parse_queue_params_js_1 = require("../queue/_/_parse-queue-params.js");
10
11
  const _has_rate_limit_exceeded_js_1 = require("./_/_has-rate-limit-exceeded.js");
11
12
  const index_js_3 = require("./errors/index.js");
12
13
  class QueueRateLimit {
@@ -20,91 +21,106 @@ class QueueRateLimit {
20
21
  this.queue = new index_js_2.Queue();
21
22
  }
22
23
  clear(queue, cb) {
23
- const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
24
- if (queueParams instanceof Error)
25
- cb(queueParams);
26
- else {
27
- this.redisClient.getSetInstance((err, client) => {
28
- if (err)
29
- cb(err);
30
- else if (!client)
31
- cb(new redis_smq_common_1.CallbackEmptyReplyError());
32
- else {
33
- const { keyQueueProperties, keyQueueRateLimitCounter } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null);
34
- const multi = client.multi();
35
- multi.hdel(keyQueueProperties, String(index_js_2.EQueueProperty.RATE_LIMIT));
36
- multi.del(keyQueueRateLimitCounter);
37
- multi.exec((err) => cb(err));
38
- }
39
- });
40
- }
24
+ this.redisClient.getSetInstance((err, client) => {
25
+ if (err)
26
+ cb(err);
27
+ else if (!client)
28
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
29
+ else
30
+ (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, (err, queueParams) => {
31
+ if (err)
32
+ cb(err);
33
+ else if (!queueParams)
34
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
35
+ else {
36
+ const { keyQueueProperties, keyQueueRateLimitCounter } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null);
37
+ const multi = client.multi();
38
+ multi.hdel(keyQueueProperties, String(index_js_2.EQueueProperty.RATE_LIMIT));
39
+ multi.del(keyQueueRateLimitCounter);
40
+ multi.exec((err) => cb(err));
41
+ }
42
+ });
43
+ });
41
44
  }
42
45
  set(queue, rateLimit, cb) {
43
- const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
44
- if (queueParams instanceof Error)
45
- cb(queueParams);
46
- else {
47
- this.redisClient.getSetInstance((err, client) => {
48
- if (err)
49
- cb(err);
50
- else if (!client)
51
- cb(new redis_smq_common_1.CallbackEmptyReplyError());
52
- else {
53
- const limit = Number(rateLimit.limit);
54
- if (isNaN(limit) || limit <= 0) {
55
- cb(new index_js_3.QueueRateLimitInvalidLimitError());
56
- }
57
- const interval = Number(rateLimit.interval);
58
- if (isNaN(interval) || interval < 1000) {
59
- cb(new index_js_3.QueueRateLimitInvalidIntervalError());
46
+ this.redisClient.getSetInstance((err, client) => {
47
+ if (err)
48
+ cb(err);
49
+ else if (!client)
50
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
51
+ else
52
+ (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, (err, queueParams) => {
53
+ if (err)
54
+ cb(err);
55
+ else if (!queueParams)
56
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
57
+ else {
58
+ const limit = Number(rateLimit.limit);
59
+ if (isNaN(limit) || limit <= 0) {
60
+ cb(new index_js_3.QueueRateLimitInvalidLimitError());
61
+ }
62
+ const interval = Number(rateLimit.interval);
63
+ if (isNaN(interval) || interval < 1000) {
64
+ cb(new index_js_3.QueueRateLimitInvalidIntervalError());
65
+ }
66
+ const validatedRateLimit = { interval, limit };
67
+ const { keyQueueProperties } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null);
68
+ client.runScript(scripts_js_1.ELuaScriptName.SET_QUEUE_RATE_LIMIT, [keyQueueProperties], [index_js_2.EQueueProperty.RATE_LIMIT, JSON.stringify(validatedRateLimit)], (err, reply) => {
69
+ if (err)
70
+ cb(err);
71
+ else if (reply !== 'OK')
72
+ cb(new index_js_3.QueueRateLimitQueueNotFoundError());
73
+ else
74
+ cb();
75
+ });
60
76
  }
61
- const validatedRateLimit = { interval, limit };
62
- const { keyQueueProperties } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null);
63
- client.hset(keyQueueProperties, String(index_js_2.EQueueProperty.RATE_LIMIT), JSON.stringify(validatedRateLimit), (err) => cb(err));
64
- }
65
- });
66
- }
77
+ });
78
+ });
67
79
  }
68
80
  hasExceeded(queue, rateLimit, cb) {
69
- const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
70
- if (queueParams instanceof Error)
71
- cb(queueParams);
72
- else {
73
- this.redisClient.getSetInstance((err, client) => {
74
- if (err)
75
- cb(err);
76
- else if (!client)
77
- cb(new redis_smq_common_1.CallbackEmptyReplyError());
78
- else
79
- (0, _has_rate_limit_exceeded_js_1._hasRateLimitExceeded)(client, queueParams, rateLimit, cb);
80
- });
81
- }
81
+ this.redisClient.getSetInstance((err, client) => {
82
+ if (err)
83
+ cb(err);
84
+ else if (!client)
85
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
86
+ else
87
+ (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, (err, queueParams) => {
88
+ if (err)
89
+ cb(err);
90
+ else if (!queueParams)
91
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
92
+ else
93
+ (0, _has_rate_limit_exceeded_js_1._hasRateLimitExceeded)(client, queueParams, rateLimit, cb);
94
+ });
95
+ });
82
96
  }
83
97
  get(queue, cb) {
84
- const queueParams = (0, _parse_queue_params_js_1._parseQueueParams)(queue);
85
- if (queueParams instanceof Error)
86
- cb(queueParams);
87
- else {
88
- this.redisClient.getSetInstance((err, client) => {
89
- if (err)
90
- cb(err);
91
- else if (!client)
92
- cb(new redis_smq_common_1.CallbackEmptyReplyError());
93
- else {
94
- const { keyQueueProperties } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null);
95
- client.hget(keyQueueProperties, String(index_js_2.EQueueProperty.RATE_LIMIT), (err, reply) => {
96
- if (err)
97
- cb(err);
98
- else if (!reply)
99
- cb(null, null);
100
- else {
101
- const rateLimit = JSON.parse(reply);
102
- cb(null, rateLimit);
103
- }
104
- });
105
- }
106
- });
107
- }
98
+ this.redisClient.getSetInstance((err, client) => {
99
+ if (err)
100
+ cb(err);
101
+ else if (!client)
102
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
103
+ else
104
+ (0, _parse_queue_params_and_validate_js_1._parseQueueParamsAndValidate)(client, queue, (err, queueParams) => {
105
+ if (err)
106
+ cb(err);
107
+ else if (!queueParams)
108
+ cb(new redis_smq_common_1.CallbackEmptyReplyError());
109
+ else {
110
+ const { keyQueueProperties } = redis_keys_js_1.redisKeys.getQueueKeys(queueParams, null);
111
+ client.hget(keyQueueProperties, String(index_js_2.EQueueProperty.RATE_LIMIT), (err, reply) => {
112
+ if (err)
113
+ cb(err);
114
+ else if (!reply)
115
+ cb(null, null);
116
+ else {
117
+ const rateLimit = JSON.parse(reply);
118
+ cb(null, rateLimit);
119
+ }
120
+ });
121
+ }
122
+ });
123
+ });
108
124
  }
109
125
  }
110
126
  exports.QueueRateLimit = QueueRateLimit;
@@ -0,0 +1,14 @@
1
+ local keyQueueProperties = KEYS[1]
2
+
3
+ ---
4
+
5
+ local EQueuePropertyRateLimit = ARGV[1]
6
+ local rateLimit = ARGV[2]
7
+
8
+ local result = redis.call("EXISTS", keyQueueProperties)
9
+ if result == 0 then
10
+ return 'QUEUE_NOT_FOUND';
11
+ end
12
+
13
+ redis.call("HSET", keyQueueProperties, EQueuePropertyRateLimit, rateLimit)
14
+ return 'OK'
@@ -11,6 +11,7 @@ export declare enum ELuaScriptName {
11
11
  DELETE_MESSAGE = "DELETE_MESSAGE",
12
12
  FETCH_MESSAGE_FOR_PROCESSING = "FETCH_MESSAGE_FOR_PROCESSING",
13
13
  DELETE_CONSUMER_GROUP = "DELETE_CONSUMER_GROUP",
14
- CLEANUP_OFFLINE_CONSUMER = "CLEANUP_OFFLINE_CONSUMER"
14
+ CLEANUP_OFFLINE_CONSUMER = "CLEANUP_OFFLINE_CONSUMER",
15
+ SET_QUEUE_RATE_LIMIT = "SET_QUEUE_RATE_LIMIT"
15
16
  }
16
17
  //# sourceMappingURL=scripts.d.ts.map
@@ -16,6 +16,7 @@ export var ELuaScriptName;
16
16
  ELuaScriptName["FETCH_MESSAGE_FOR_PROCESSING"] = "FETCH_MESSAGE_FOR_PROCESSING";
17
17
  ELuaScriptName["DELETE_CONSUMER_GROUP"] = "DELETE_CONSUMER_GROUP";
18
18
  ELuaScriptName["CLEANUP_OFFLINE_CONSUMER"] = "CLEANUP_OFFLINE_CONSUMER";
19
+ ELuaScriptName["SET_QUEUE_RATE_LIMIT"] = "SET_QUEUE_RATE_LIMIT";
19
20
  })(ELuaScriptName = ELuaScriptName || (ELuaScriptName = {}));
20
21
  RedisClientAbstract.addScript(ELuaScriptName.PUBLISH_SCHEDULED_MESSAGE, fs
21
22
  .readFileSync(resolve(getDirname(), './lua/publish-scheduled-message.lua'))
@@ -52,4 +53,7 @@ RedisClientAbstract.addScript(ELuaScriptName.DELETE_CONSUMER_GROUP, fs
52
53
  RedisClientAbstract.addScript(ELuaScriptName.CLEANUP_OFFLINE_CONSUMER, fs
53
54
  .readFileSync(resolve(getDirname(), './lua/cleanup-offline-consumer.lua'))
54
55
  .toString());
56
+ RedisClientAbstract.addScript(ELuaScriptName.SET_QUEUE_RATE_LIMIT, fs
57
+ .readFileSync(resolve(getDirname(), './lua/set-queue-rate-limit.lua'))
58
+ .toString());
55
59
  //# sourceMappingURL=scripts.js.map
@@ -1,3 +1,4 @@
1
1
  export { NamespaceNotFoundError } from './namespace-not-found.error.js';
2
2
  export { NamespaceError } from './namespace.error.js';
3
+ export { NamespaceInvalidNamespaceError } from './namespace-invalid-namespace.error.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,4 @@
1
1
  export { NamespaceNotFoundError } from './namespace-not-found.error.js';
2
2
  export { NamespaceError } from './namespace.error.js';
3
+ export { NamespaceInvalidNamespaceError } from './namespace-invalid-namespace.error.js';
3
4
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,4 @@
1
+ import { NamespaceError } from './namespace.error.js';
2
+ export declare class NamespaceInvalidNamespaceError extends NamespaceError {
3
+ }
4
+ //# sourceMappingURL=namespace-invalid-namespace.error.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { NamespaceError } from './namespace.error.js';
2
+ export class NamespaceInvalidNamespaceError extends NamespaceError {
3
+ }
4
+ //# sourceMappingURL=namespace-invalid-namespace.error.js.map
@@ -4,7 +4,7 @@ import { redisKeys } from '../../common/redis-keys/redis-keys.js';
4
4
  import { Configuration } from '../../config/index.js';
5
5
  import { _deleteQueue } from '../queue/_/_delete-queue.js';
6
6
  import { _getQueues } from '../queue/_/_get-queues.js';
7
- import { NamespaceNotFoundError } from './errors/index.js';
7
+ import { NamespaceInvalidNamespaceError, NamespaceNotFoundError, } from './errors/index.js';
8
8
  export class Namespace {
9
9
  logger;
10
10
  redisClient;
@@ -35,7 +35,7 @@ export class Namespace {
35
35
  getNamespaceQueues(namespace, cb) {
36
36
  const ns = redisKeys.validateRedisKey(namespace);
37
37
  if (ns instanceof Error)
38
- cb(ns);
38
+ cb(new NamespaceInvalidNamespaceError());
39
39
  else {
40
40
  this.redisClient.getSetInstance((err, client) => {
41
41
  if (err)
@@ -76,7 +76,7 @@ export class Namespace {
76
76
  delete(namespace, cb) {
77
77
  const ns = redisKeys.validateRedisKey(namespace);
78
78
  if (ns instanceof Error)
79
- cb(ns);
79
+ cb(new NamespaceInvalidNamespaceError());
80
80
  else {
81
81
  this.redisClient.getSetInstance((err, client) => {
82
82
  if (err)
@@ -11,7 +11,7 @@ export function _parseQueueExtendedParams(args) {
11
11
  if (typeof args === 'string') {
12
12
  const queueParams = _parseQueueParams(args);
13
13
  if (queueParams instanceof Error)
14
- return new QueueInvalidQueueParameterError();
14
+ return queueParams;
15
15
  return {
16
16
  queueParams,
17
17
  groupId: null,
@@ -20,7 +20,7 @@ export function _parseQueueExtendedParams(args) {
20
20
  if (isQueueParams(args)) {
21
21
  const queueParams = _parseQueueParams(args);
22
22
  if (queueParams instanceof Error)
23
- return new QueueInvalidQueueParameterError();
23
+ return queueParams;
24
24
  return {
25
25
  queueParams,
26
26
  groupId: null,
@@ -0,0 +1,4 @@
1
+ import { ICallback, IRedisClient } from 'redis-smq-common';
2
+ import { IQueueParams } from '../types/queue.js';
3
+ export declare function _parseQueueParamsAndValidate(redisClient: IRedisClient, queue: string | IQueueParams, cb: ICallback<IQueueParams>): void;
4
+ //# sourceMappingURL=_parse-queue-params-and-validate.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { QueueQueueNotFoundError } from '../errors/queue-queue-not-found.error.js';
2
+ import { _parseQueueParams } from './_parse-queue-params.js';
3
+ import { _queueExists } from './_queue-exists.js';
4
+ export function _parseQueueParamsAndValidate(redisClient, queue, cb) {
5
+ const queueParams = _parseQueueParams(queue);
6
+ if (queueParams instanceof Error)
7
+ cb(queueParams);
8
+ else
9
+ _queueExists(redisClient, queueParams, (err, reply) => {
10
+ if (err)
11
+ cb(err);
12
+ else if (!reply)
13
+ cb(new QueueQueueNotFoundError());
14
+ else
15
+ cb(null, queueParams);
16
+ });
17
+ }
18
+ //# sourceMappingURL=_parse-queue-params-and-validate.js.map
@@ -0,0 +1,4 @@
1
+ import { ICallback, IRedisClient } from 'redis-smq-common';
2
+ import { IQueueParams } from '../types/queue.js';
3
+ export declare function _queueExists(redisClient: IRedisClient, queue: IQueueParams, cb: ICallback<boolean>): void;
4
+ //# sourceMappingURL=_queue-exists.d.ts.map
@@ -0,0 +1,11 @@
1
+ import { redisKeys } from '../../../common/redis-keys/redis-keys.js';
2
+ export function _queueExists(redisClient, queue, cb) {
3
+ const { keyQueues } = redisKeys.getMainKeys();
4
+ redisClient.sismember(keyQueues, JSON.stringify(queue), (err, reply) => {
5
+ if (err)
6
+ cb(err);
7
+ else
8
+ cb(null, !!reply);
9
+ });
10
+ }
11
+ //# sourceMappingURL=_queue-exists.js.map
@@ -8,6 +8,7 @@ import { _deleteQueue } from './_/_delete-queue.js';
8
8
  import { _getQueueProperties } from './_/_get-queue-properties.js';
9
9
  import { _getQueues } from './_/_get-queues.js';
10
10
  import { _parseQueueParams } from './_/_parse-queue-params.js';
11
+ import { _queueExists } from './_/_queue-exists.js';
11
12
  import { QueueQueueExistsError } from './errors/index.js';
12
13
  import { EQueueProperty, } from './types/index.js';
13
14
  export class Queue {
@@ -82,15 +83,8 @@ export class Queue {
82
83
  cb(err);
83
84
  else if (!client)
84
85
  cb(new CallbackEmptyReplyError());
85
- else {
86
- const { keyQueues } = redisKeys.getMainKeys();
87
- client.sismember(keyQueues, JSON.stringify(queueParams), (err, reply) => {
88
- if (err)
89
- cb(err);
90
- else
91
- cb(null, !!reply);
92
- });
93
- }
86
+ else
87
+ _queueExists(client, queueParams, cb);
94
88
  });
95
89
  }
96
90
  }
@@ -1,4 +1,5 @@
1
1
  export { QueueRateLimitError } from './queue-rate-limit.error.js';
2
2
  export { QueueRateLimitInvalidIntervalError } from './queue-rate-limit-invalid-interval.error.js';
3
3
  export { QueueRateLimitInvalidLimitError } from './queue-rate-limit-invalid-limit.error.js';
4
+ export { QueueRateLimitQueueNotFoundError } from './queue-rate-limit-queue-not-found.error.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,5 @@
1
1
  export { QueueRateLimitError } from './queue-rate-limit.error.js';
2
2
  export { QueueRateLimitInvalidIntervalError } from './queue-rate-limit-invalid-interval.error.js';
3
3
  export { QueueRateLimitInvalidLimitError } from './queue-rate-limit-invalid-limit.error.js';
4
+ export { QueueRateLimitQueueNotFoundError } from './queue-rate-limit-queue-not-found.error.js';
4
5
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,4 @@
1
+ import { QueueRateLimitError } from './queue-rate-limit.error.js';
2
+ export declare class QueueRateLimitQueueNotFoundError extends QueueRateLimitError {
3
+ }
4
+ //# sourceMappingURL=queue-rate-limit-queue-not-found.error.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { QueueRateLimitError } from './queue-rate-limit.error.js';
2
+ export class QueueRateLimitQueueNotFoundError extends QueueRateLimitError {
3
+ }
4
+ //# sourceMappingURL=queue-rate-limit-queue-not-found.error.js.map
@@ -1,11 +1,12 @@
1
1
  import { async, CallbackEmptyReplyError, logger, } from 'redis-smq-common';
2
2
  import { RedisClientInstance } from '../../common/redis-client/redis-client-instance.js';
3
+ import { ELuaScriptName } from '../../common/redis-client/scripts/scripts.js';
3
4
  import { redisKeys } from '../../common/redis-keys/redis-keys.js';
4
5
  import { Configuration } from '../../config/index.js';
6
+ import { _parseQueueParamsAndValidate } from '../queue/_/_parse-queue-params-and-validate.js';
5
7
  import { EQueueProperty, Queue, } from '../queue/index.js';
6
- import { _parseQueueParams } from '../queue/_/_parse-queue-params.js';
7
8
  import { _hasRateLimitExceeded } from './_/_has-rate-limit-exceeded.js';
8
- import { QueueRateLimitInvalidLimitError, QueueRateLimitInvalidIntervalError, } from './errors/index.js';
9
+ import { QueueRateLimitInvalidLimitError, QueueRateLimitInvalidIntervalError, QueueRateLimitQueueNotFoundError, } from './errors/index.js';
9
10
  export class QueueRateLimit {
10
11
  redisClient;
11
12
  logger;
@@ -17,91 +18,106 @@ export class QueueRateLimit {
17
18
  this.queue = new Queue();
18
19
  }
19
20
  clear(queue, cb) {
20
- const queueParams = _parseQueueParams(queue);
21
- if (queueParams instanceof Error)
22
- cb(queueParams);
23
- else {
24
- this.redisClient.getSetInstance((err, client) => {
25
- if (err)
26
- cb(err);
27
- else if (!client)
28
- cb(new CallbackEmptyReplyError());
29
- else {
30
- const { keyQueueProperties, keyQueueRateLimitCounter } = redisKeys.getQueueKeys(queueParams, null);
31
- const multi = client.multi();
32
- multi.hdel(keyQueueProperties, String(EQueueProperty.RATE_LIMIT));
33
- multi.del(keyQueueRateLimitCounter);
34
- multi.exec((err) => cb(err));
35
- }
36
- });
37
- }
21
+ this.redisClient.getSetInstance((err, client) => {
22
+ if (err)
23
+ cb(err);
24
+ else if (!client)
25
+ cb(new CallbackEmptyReplyError());
26
+ else
27
+ _parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
28
+ if (err)
29
+ cb(err);
30
+ else if (!queueParams)
31
+ cb(new CallbackEmptyReplyError());
32
+ else {
33
+ const { keyQueueProperties, keyQueueRateLimitCounter } = redisKeys.getQueueKeys(queueParams, null);
34
+ const multi = client.multi();
35
+ multi.hdel(keyQueueProperties, String(EQueueProperty.RATE_LIMIT));
36
+ multi.del(keyQueueRateLimitCounter);
37
+ multi.exec((err) => cb(err));
38
+ }
39
+ });
40
+ });
38
41
  }
39
42
  set(queue, rateLimit, cb) {
40
- const queueParams = _parseQueueParams(queue);
41
- if (queueParams instanceof Error)
42
- cb(queueParams);
43
- else {
44
- this.redisClient.getSetInstance((err, client) => {
45
- if (err)
46
- cb(err);
47
- else if (!client)
48
- cb(new CallbackEmptyReplyError());
49
- else {
50
- const limit = Number(rateLimit.limit);
51
- if (isNaN(limit) || limit <= 0) {
52
- cb(new QueueRateLimitInvalidLimitError());
53
- }
54
- const interval = Number(rateLimit.interval);
55
- if (isNaN(interval) || interval < 1000) {
56
- cb(new QueueRateLimitInvalidIntervalError());
43
+ this.redisClient.getSetInstance((err, client) => {
44
+ if (err)
45
+ cb(err);
46
+ else if (!client)
47
+ cb(new CallbackEmptyReplyError());
48
+ else
49
+ _parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
50
+ if (err)
51
+ cb(err);
52
+ else if (!queueParams)
53
+ cb(new CallbackEmptyReplyError());
54
+ else {
55
+ const limit = Number(rateLimit.limit);
56
+ if (isNaN(limit) || limit <= 0) {
57
+ cb(new QueueRateLimitInvalidLimitError());
58
+ }
59
+ const interval = Number(rateLimit.interval);
60
+ if (isNaN(interval) || interval < 1000) {
61
+ cb(new QueueRateLimitInvalidIntervalError());
62
+ }
63
+ const validatedRateLimit = { interval, limit };
64
+ const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
65
+ client.runScript(ELuaScriptName.SET_QUEUE_RATE_LIMIT, [keyQueueProperties], [EQueueProperty.RATE_LIMIT, JSON.stringify(validatedRateLimit)], (err, reply) => {
66
+ if (err)
67
+ cb(err);
68
+ else if (reply !== 'OK')
69
+ cb(new QueueRateLimitQueueNotFoundError());
70
+ else
71
+ cb();
72
+ });
57
73
  }
58
- const validatedRateLimit = { interval, limit };
59
- const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
60
- client.hset(keyQueueProperties, String(EQueueProperty.RATE_LIMIT), JSON.stringify(validatedRateLimit), (err) => cb(err));
61
- }
62
- });
63
- }
74
+ });
75
+ });
64
76
  }
65
77
  hasExceeded(queue, rateLimit, cb) {
66
- const queueParams = _parseQueueParams(queue);
67
- if (queueParams instanceof Error)
68
- cb(queueParams);
69
- else {
70
- this.redisClient.getSetInstance((err, client) => {
71
- if (err)
72
- cb(err);
73
- else if (!client)
74
- cb(new CallbackEmptyReplyError());
75
- else
76
- _hasRateLimitExceeded(client, queueParams, rateLimit, cb);
77
- });
78
- }
78
+ this.redisClient.getSetInstance((err, client) => {
79
+ if (err)
80
+ cb(err);
81
+ else if (!client)
82
+ cb(new CallbackEmptyReplyError());
83
+ else
84
+ _parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
85
+ if (err)
86
+ cb(err);
87
+ else if (!queueParams)
88
+ cb(new CallbackEmptyReplyError());
89
+ else
90
+ _hasRateLimitExceeded(client, queueParams, rateLimit, cb);
91
+ });
92
+ });
79
93
  }
80
94
  get(queue, cb) {
81
- const queueParams = _parseQueueParams(queue);
82
- if (queueParams instanceof Error)
83
- cb(queueParams);
84
- else {
85
- this.redisClient.getSetInstance((err, client) => {
86
- if (err)
87
- cb(err);
88
- else if (!client)
89
- cb(new CallbackEmptyReplyError());
90
- else {
91
- const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
92
- client.hget(keyQueueProperties, String(EQueueProperty.RATE_LIMIT), (err, reply) => {
93
- if (err)
94
- cb(err);
95
- else if (!reply)
96
- cb(null, null);
97
- else {
98
- const rateLimit = JSON.parse(reply);
99
- cb(null, rateLimit);
100
- }
101
- });
102
- }
103
- });
104
- }
95
+ this.redisClient.getSetInstance((err, client) => {
96
+ if (err)
97
+ cb(err);
98
+ else if (!client)
99
+ cb(new CallbackEmptyReplyError());
100
+ else
101
+ _parseQueueParamsAndValidate(client, queue, (err, queueParams) => {
102
+ if (err)
103
+ cb(err);
104
+ else if (!queueParams)
105
+ cb(new CallbackEmptyReplyError());
106
+ else {
107
+ const { keyQueueProperties } = redisKeys.getQueueKeys(queueParams, null);
108
+ client.hget(keyQueueProperties, String(EQueueProperty.RATE_LIMIT), (err, reply) => {
109
+ if (err)
110
+ cb(err);
111
+ else if (!reply)
112
+ cb(null, null);
113
+ else {
114
+ const rateLimit = JSON.parse(reply);
115
+ cb(null, rateLimit);
116
+ }
117
+ });
118
+ }
119
+ });
120
+ });
105
121
  }
106
122
  shutdown = (cb) => {
107
123
  async.waterfall([this.queue.shutdown, this.redisClient.shutdown], cb);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "redis-smq",
3
- "version": "8.0.0-rc.23",
3
+ "version": "8.0.0-rc.24",
4
4
  "description": "A simple high-performance Redis message queue for Node.js.",
5
5
  "author": "Weyoss <weyoss@protonmail.com>",
6
6
  "license": "MIT",