redis-smq 3.0.3 → 3.2.0

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 (126) hide show
  1. package/CHANGELOG.md +26 -5
  2. package/README.md +89 -24
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +2 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/consumer.d.ts +15 -17
  7. package/dist/src/consumer.js +118 -96
  8. package/dist/src/consumer.js.map +1 -1
  9. package/dist/src/events.d.ts +11 -14
  10. package/dist/src/events.js +11 -14
  11. package/dist/src/events.js.map +1 -1
  12. package/dist/src/gc-message-collector.d.ts +10 -7
  13. package/dist/src/gc-message-collector.js +20 -13
  14. package/dist/src/gc-message-collector.js.map +1 -1
  15. package/dist/src/gc.d.ts +18 -17
  16. package/dist/src/gc.js +149 -134
  17. package/dist/src/gc.js.map +1 -1
  18. package/dist/src/heartbeat-monitor.js +20 -18
  19. package/dist/src/heartbeat-monitor.js.map +1 -1
  20. package/dist/src/heartbeat.d.ts +40 -13
  21. package/dist/src/heartbeat.js +170 -181
  22. package/dist/src/heartbeat.js.map +1 -1
  23. package/dist/src/instance.d.ts +37 -22
  24. package/dist/src/instance.js +62 -112
  25. package/dist/src/instance.js.map +1 -1
  26. package/dist/src/lock-manager.d.ts +5 -7
  27. package/dist/src/lock-manager.js +7 -16
  28. package/dist/src/lock-manager.js.map +1 -1
  29. package/dist/src/logger.d.ts +1 -1
  30. package/dist/src/logger.js +7 -3
  31. package/dist/src/logger.js.map +1 -1
  32. package/dist/src/message.js.map +1 -1
  33. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message-request.DTO.d.ts +4 -0
  34. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message-request.DTO.js +25 -0
  35. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message-request.DTO.js.map +1 -0
  36. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message-response.DTO.d.ts +4 -0
  37. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message-response.DTO.js +26 -0
  38. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message-response.DTO.js.map +1 -0
  39. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message.handler.d.ts +5 -0
  40. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message.handler.js +20 -0
  41. package/dist/src/monitor-server/controllers/scheduler/actions/delete-scheduled-message/delete-scheduled-message.handler.js.map +1 -0
  42. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages-request.DTO.d.ts +5 -0
  43. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages-request.DTO.js +34 -0
  44. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages-request.DTO.js.map +1 -0
  45. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages-response.DTO.d.ts +28 -0
  46. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages-response.DTO.js +128 -0
  47. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages-response.DTO.js.map +1 -0
  48. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages.handler.d.ts +6 -0
  49. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages.handler.js +20 -0
  50. package/dist/src/monitor-server/controllers/scheduler/actions/get-scheduled-messages/get-scheduled-messages.handler.js.map +1 -0
  51. package/dist/src/monitor-server/controllers/scheduler/index.d.ts +25 -0
  52. package/dist/src/monitor-server/controllers/scheduler/index.js +32 -0
  53. package/dist/src/monitor-server/controllers/scheduler/index.js.map +1 -0
  54. package/dist/src/monitor-server/index.d.ts +9 -0
  55. package/dist/src/monitor-server/index.js +120 -0
  56. package/dist/src/monitor-server/index.js.map +1 -0
  57. package/dist/src/monitor-server/lib/routing.d.ts +29 -0
  58. package/dist/src/monitor-server/lib/routing.js +61 -0
  59. package/dist/src/monitor-server/lib/routing.js.map +1 -0
  60. package/dist/src/monitor-server/middlewares/error-handler.d.ts +2 -0
  61. package/dist/src/monitor-server/middlewares/error-handler.js +42 -0
  62. package/dist/src/monitor-server/middlewares/error-handler.js.map +1 -0
  63. package/dist/src/monitor-server/middlewares/request-validator.d.ts +4 -0
  64. package/dist/src/monitor-server/middlewares/request-validator.js +23 -0
  65. package/dist/src/monitor-server/middlewares/request-validator.js.map +1 -0
  66. package/dist/src/monitor-server/middlewares/response-validator.d.ts +3 -0
  67. package/dist/src/monitor-server/middlewares/response-validator.js +25 -0
  68. package/dist/src/monitor-server/middlewares/response-validator.js.map +1 -0
  69. package/dist/src/monitor-server/services/index.d.ts +5 -0
  70. package/dist/src/monitor-server/services/index.js +18 -0
  71. package/dist/src/monitor-server/services/index.js.map +1 -0
  72. package/dist/src/monitor-server/services/scheduler.service.d.ts +10 -0
  73. package/dist/src/monitor-server/services/scheduler.service.js +50 -0
  74. package/dist/src/monitor-server/services/scheduler.service.js.map +1 -0
  75. package/dist/src/{stats-aggregator.d.ts → monitor-server/threads/stats-aggregator.thread.d.ts} +0 -0
  76. package/dist/src/{stats-aggregator.js → monitor-server/threads/stats-aggregator.thread.js} +61 -68
  77. package/dist/src/monitor-server/threads/stats-aggregator.thread.js.map +1 -0
  78. package/dist/src/monitor-server/types/common.d.ts +39 -0
  79. package/dist/src/monitor-server/types/common.js +3 -0
  80. package/dist/src/monitor-server/types/common.js.map +1 -0
  81. package/dist/src/monitor-server/utils/thread-runner.d.ts +3 -0
  82. package/dist/src/monitor-server/utils/thread-runner.js +57 -0
  83. package/dist/src/monitor-server/utils/thread-runner.js.map +1 -0
  84. package/dist/src/monitor-server/utils/validate-dto.d.ts +2 -0
  85. package/dist/src/monitor-server/utils/validate-dto.js +31 -0
  86. package/dist/src/monitor-server/utils/validate-dto.js.map +1 -0
  87. package/dist/src/producer.d.ts +3 -4
  88. package/dist/src/producer.js +24 -23
  89. package/dist/src/producer.js.map +1 -1
  90. package/dist/src/queue-helpers.d.ts +10 -0
  91. package/dist/src/queue-helpers.js +45 -0
  92. package/dist/src/queue-helpers.js.map +1 -0
  93. package/dist/src/redis-client.d.ts +25 -21
  94. package/dist/src/redis-client.js +39 -18
  95. package/dist/src/redis-client.js.map +1 -1
  96. package/dist/src/redis-keys.d.ts +91 -0
  97. package/dist/src/redis-keys.js +156 -0
  98. package/dist/src/redis-keys.js.map +1 -0
  99. package/dist/src/scheduler-runner.d.ts +29 -0
  100. package/dist/src/scheduler-runner.js +111 -0
  101. package/dist/src/scheduler-runner.js.map +1 -0
  102. package/dist/src/scheduler.d.ts +15 -29
  103. package/dist/src/scheduler.js +149 -149
  104. package/dist/src/scheduler.js.map +1 -1
  105. package/dist/src/stats.d.ts +5 -9
  106. package/dist/src/stats.js +33 -45
  107. package/dist/src/stats.js.map +1 -1
  108. package/dist/src/ticker.d.ts +4 -3
  109. package/dist/src/ticker.js +29 -22
  110. package/dist/src/ticker.js.map +1 -1
  111. package/dist/tsconfig.tsbuildinfo +1 -1
  112. package/dist/types/index.d.ts +19 -4
  113. package/dist/types/index.js.map +1 -1
  114. package/docs/api/consumer.md +1 -1
  115. package/docs/api/scheduler.md +135 -0
  116. package/package.json +37 -16
  117. package/dist/src/redis-keys/consumer-redis-keys.d.ts +0 -57
  118. package/dist/src/redis-keys/consumer-redis-keys.js +0 -78
  119. package/dist/src/redis-keys/consumer-redis-keys.js.map +0 -1
  120. package/dist/src/redis-keys/mq-redis-keys.d.ts +0 -30
  121. package/dist/src/redis-keys/mq-redis-keys.js +0 -95
  122. package/dist/src/redis-keys/mq-redis-keys.js.map +0 -1
  123. package/dist/src/redis-keys/producer-redis-keys.d.ts +0 -25
  124. package/dist/src/redis-keys/producer-redis-keys.js +0 -36
  125. package/dist/src/redis-keys/producer-redis-keys.js.map +0 -1
  126. package/dist/src/stats-aggregator.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,9 +1,29 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 3.0.3 (2021-09-08)
3
+ ## 3.2.0 (2021-10-01)
4
+
5
+ - Run tests in Node.js v12, v14, and v16
6
+ - Run tests in Redis v2.6.17, v3, v4, v5, and v6
7
+ - Made redis-smq-monitor server an integral part of redis-smq
8
+ - Implemented Scheduler HTTP API endpoints
9
+ - Various fixes and improvements
10
+
11
+ ## 3.1.1 (2021-09-16)
12
+
13
+ * Added Github CI
14
+
15
+ ## 3.1.0 (2021-09-15)
4
16
 
5
- * Fixed .npmignore
17
+ * Added Scheduler API docs.
18
+ * Added new methods to fetch and delete scheduled messages.
19
+
20
+ ## 3.0.4 (2021-09-08)
21
+
22
+ * Updated examples.
23
+
24
+ ## 3.0.3 (2021-09-08)
6
25
 
26
+ * Fixed .npmignore.
7
27
 
8
28
  ## 3.0.2 (2021-09-08)
9
29
 
@@ -15,10 +35,11 @@
15
35
 
16
36
  ## 3.0.0 (2021-09-08)
17
37
 
18
- * A major release v3.0.0 is out.
38
+ * A major release v3 is out.
39
+ * Starting from this release, only active LTS and maintenance LTS Node.js releases are supported.
19
40
  * Upgrading your installation to the newest version should be straightforward as most APIs are compatible with some exceptions.
20
- * Project codebase has been migrated to TypeScript to make use of strong typings.
21
- * JavaScript's users are always first class citizens and backward compatibility with old NodeJS versions has been kept, down to v7.0.0.
41
+ * Project codebase has been migrated to TypeScript to make use of strong typings.
42
+ * JavaScript's users are always first class citizens.
22
43
  * Fixed a compatibility issue between ioredis and redis when calling multi.exec().
23
44
  * Fixed typing inconsistencies (ConfigRedisDriver and RedisDriver types) between redis-smq and redis-smq-monitor.
24
45
  * Improved scheduler mechanics, refactored GC, and updated tests.
package/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # RedisSMQ - Yet another simple Redis message queue
2
2
 
3
+ [![Tests](https://github.com/weyoss/redis-smq/actions/workflows/tests.yml/badge.svg)](https://github.com/weyoss/redis-smq/actions/workflows/tests.yml)
4
+ [![Coverage Status](https://img.shields.io/coveralls/github/weyoss/redis-smq.svg)](https://coveralls.io/r/weyoss/redis-smq?branch=master)
5
+ [![Dependencies Status](https://img.shields.io/david/weyoss/redis-smq.svg)]((https://david-dm.org/weyoss/redis-smq))
6
+ [![NPM version](http://img.shields.io/npm/v/redis-smq.svg)](https://npmjs.org/package/redis-smq)
7
+ [![NPM downloads](https://img.shields.io/npm/dm/redis-smq.svg)](https://npmjs.org/package/redis-smq)
8
+ [![Code quality](https://img.shields.io/lgtm/grade/javascript/github/weyoss/redis-smq.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/weyoss/redis-smq/context:javascript)
9
+
3
10
  A simple high-performance Redis message queue for Node.js.
4
11
 
5
12
  For more details about RedisSMQ design see [https://medium.com/@weyoss/building-a-simple-message-queue-using-redis-server-and-node-js-964eda240a2a](https://medium.com/@weyoss/building-a-simple-message-queue-using-redis-server-and-node-js-964eda240a2a)
@@ -35,6 +42,7 @@ For more details about RedisSMQ design see [https://medium.com/@weyoss/building-
35
42
  1. [Message Class](#message-class)
36
43
  2. [Producer Class](#producer-class)
37
44
  3. [Consumer Class](#consumer-class)
45
+ 4. [Message Scheduler](#message-scheduler)
38
46
  5. [Performance](#performance)
39
47
  1. [Scenarios](#scenarios)
40
48
  2. [Environment](#environment)
@@ -49,10 +57,10 @@ For more details about RedisSMQ design see [https://medium.com/@weyoss/building-
49
57
 
50
58
  **2021.09.08**
51
59
 
52
- - A major release v3.0.0 is out.
60
+ - A major release v3 is out.
53
61
  - Upgrading your installation to the newest version should be straightforward as most APIs are compatible, [with some exceptions](docs/migrating-from-v2-to-v3.md).
54
62
  - The project's code base has been migrated to TypeScript to make use of strong typings.
55
- - JavaScript's users are always first class citizens and backward compatibility with old NodeJS versions has been kept, down to v7.0.0
63
+ - JavaScript's users are always first class citizens.
56
64
 
57
65
  See [CHANGELOG](CHANGELOG.md) for more details.
58
66
 
@@ -64,8 +72,8 @@ npm install redis-smq --save
64
72
 
65
73
  Considerations:
66
74
 
67
- - Minimal Node.js version support is 7.0.0 (with --harmony flag), 7.6.0 (without --harmony flag). The latest stable
68
- Node.js version is recommended.
75
+ - RedisSMQ is targeted to be used in production environments. Therefore, only active LTS and maintenance LTS Node.js
76
+ releases (v12, v14, and v16) are supported. The latest stable Node.js version is recommended.
69
77
  - Minimal Redis server version is 2.6.12.
70
78
 
71
79
  # Configuration
@@ -133,11 +141,11 @@ module.exports = {
133
141
 
134
142
  - `monitor` *(Object): Optional.* RedisSMQ monitor parameters.
135
143
 
136
- - `monitor.enabled` *(Boolean/Integer): Optional.* Enable/Disable the monitor. By default disabled.
144
+ - `monitor.enabled` *(Boolean/Integer): Optional.* Enable/Disable the monitor. By default, disabled.
137
145
 
138
- - `monitor.host` *(String): Optional.* IP address of the monitor server. By default `0.0.0.0`.
146
+ - `monitor.host` *(String): Optional.* IP address of the monitor server. By default, `0.0.0.0`.
139
147
 
140
- - `monitor.port` *(Integer): Optional.* Port of the monitor server. By default `7210`.
148
+ - `monitor.port` *(Integer): Optional.* Port of the monitor server. By default, `7210`.
141
149
 
142
150
  ## Usage
143
151
 
@@ -149,11 +157,8 @@ Message class is the main component responsible for creating and handling messag
149
157
  the required methods needed to construct and deal with messages.
150
158
 
151
159
  ```javascript
152
-
153
160
  const { Message } = require('redis-smq');
154
-
155
161
  const message = new Message();
156
-
157
162
  message
158
163
  .setBody({hello: 'world'})
159
164
  .setTTL(3600000)
@@ -176,7 +181,7 @@ Each producer instance has an associated message queue and provides `produceMess
176
181
  message and decides to either send it to the message queue scheduler or to immediately enqueue it for delivery.
177
182
 
178
183
  ```javascript
179
- // filename: ./example/test-queue-producer.js
184
+ // filename: ./examples/javascript/ns1-test-queue-producer.js
180
185
 
181
186
  'use strict';
182
187
  const { Message, Producer } = require('redis-smq');
@@ -185,8 +190,7 @@ const message = new Message();
185
190
 
186
191
  message
187
192
  .setBody({hello: 'world'})
188
- .setTTL(3600000)
189
- .setScheduledDelay(10);
193
+ .setTTL(3600000);
190
194
 
191
195
  const producer = new Producer('test_queue');
192
196
  producer.produceMessage(message, (err) => {
@@ -207,8 +211,7 @@ Consumer classes are saved per files. Each consumer file represents a consumer c
207
211
  A consumer class may look like:
208
212
 
209
213
  ```javascript
210
- // filename: ./example/test-queue-consumer.js
211
-
214
+ // filename: ./examples/javascript/ns1-test-queue-consumer.js
212
215
  'use strict';
213
216
 
214
217
  const { Consumer } = require('redis-smq');
@@ -242,7 +245,7 @@ To start consuming messages, a consumer needs first to be launched from CLI to c
242
245
  and wait for messages:
243
246
 
244
247
  ```text
245
- $ node ./example/test-queue-consumer.js
248
+ $ node ./examples/javascript/test-queue-consumer.js
246
249
  ```
247
250
 
248
251
  Once a message is received and processed the consumer should acknowledge the message by invoking the callback function
@@ -257,6 +260,67 @@ corresponding queue called dead-letter queue where all failed to consume message
257
260
 
258
261
  See [Consumer API Reference](docs/api/consumer.md) for more details.
259
262
 
263
+ ### Message Scheduler
264
+
265
+ Message Scheduler enables you to schedule a one-time or repeating messages in your MQ server.
266
+
267
+ The [Message API](docs/api/message.md) provides many methods:
268
+
269
+ - [setScheduledPeriod()](docs/api/message.md#messageprototypesetscheduledperiod)
270
+ - [setScheduledDelay()](docs/api/message.md#messageprototypesetscheduleddelay)
271
+ - [setScheduledCron()](docs/api/message.md#messageprototypesetscheduledcron)
272
+ - [setScheduledRepeat()](docs/api/message.md#messageprototypesetscheduledrepeat)
273
+
274
+ in order to set up scheduling parameters for a specific message. Once your message is ready, you can use
275
+ [producer.produceMessage()](docs/api/producer.md#producerprototypeproducemessage) to publish it.
276
+
277
+ Under the hood, the `producer` invokes `isSchedulable()` and `schedule()` of the [Scheduler class](docs/api/scheduler.md)
278
+ to place your message in the delay queue.
279
+
280
+ ```javascript
281
+ 'use strict';
282
+ const { Message, Producer } = require('redis-smq');
283
+
284
+ const producer = new Producer('test_queue');
285
+
286
+ const message = new Message();
287
+ message
288
+ .setBody({hello: 'world'})
289
+ .setScheduledCron(`0 0 * * * *`);
290
+
291
+ producer.produceMessage(message, (err) => {
292
+ if (err) console.log(err);
293
+ else console.log('Message has been succefully produced');
294
+ })
295
+ ```
296
+
297
+ Alternatively, you can also manually get the scheduler instance from the producer using `producer.getScheduler()`
298
+ and call the `schedule()` method as shown in the example bellow:
299
+
300
+ ```javascript
301
+ 'use strict';
302
+ const { Message, Producer } = require('redis-smq');
303
+
304
+ const producer = new Producer('test_queue');
305
+
306
+ producer.getScheduler((err, scheduler) => {
307
+ if (err) console.log(err);
308
+ else {
309
+ const message = new Message();
310
+ message
311
+ .setBody({hello: 'world'})
312
+ .setScheduledCron(`0 0 * * * *`);
313
+ scheduler.schedule(message, (err, reply) => {
314
+ if (err) console.log(err);
315
+ else if (rely) console.log('Message has been succefully scheduled');
316
+ else console.log('Message has not been scheduled');
317
+ });
318
+ }
319
+ })
320
+ ```
321
+
322
+ See [Scheduler API Reference](docs/api/scheduler.md) for more details.
323
+
260
324
  ## Performance
261
325
 
262
326
  One key indicator about how RedisSMQ is fast and performant is Message throughput. Message throughput is the number of
@@ -315,23 +379,24 @@ $ node consumer | ./node_modules/.bin/bunyan
315
379
  ```
316
380
  ### Monitoring
317
381
 
318
- The RedisSMQ Monitor is an interface which let you monitor and debug your RedisSMQ server from a web browser in
382
+ The RedisSMQ Monitor is an interface which let you monitor, debug, and manage your RedisSMQ server from a web browser in
319
383
  real-time.
320
384
 
321
- Starting from version v1.1.0, RedisSMQ Monitor has split up into a standalone project and was packaged under
322
- [RedisSMQ Monitor](https://github.com/weyoss/redis-smq-monitor)
385
+ Starting from version v1.1.0, the frontend part of the RedisSMQ Monitor has split up into a standalone project and
386
+ is packaged under [RedisSMQ Monitor](https://github.com/weyoss/redis-smq-monitor)
323
387
 
324
- RedisSMQ includes the monitor as part of its package.
388
+ Being an integral part of the MQ, the monitor can be launched and used by starting first the monitor server as shown
389
+ in the example bellow:
325
390
 
326
391
  ```javascript
327
- // filename: ./example/monitor.js
392
+ // filename: ./examples/javascript/monitor.js
328
393
  'use strict';
329
394
 
330
395
  const config = require('./config');
331
- const { monitor } = require('redis-smq');
396
+ const { MonitorServer } = require('redis-smq');
332
397
 
333
- monitor(config).listen(() => {
334
- console.log('It works!')
398
+ MonitorServer(config).listen(() => {
399
+ console.log('It works!');
335
400
  });
336
401
  ```
337
402
  ## Contributing
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Consumer } from './src/consumer';
2
2
  export { Producer } from './src/producer';
3
3
  export { Message } from './src/message';
4
- export { MonitorServer } from 'redis-smq-monitor';
4
+ export { MonitorServer } from './src/monitor-server';
package/dist/index.js CHANGED
@@ -7,6 +7,6 @@ var producer_1 = require("./src/producer");
7
7
  Object.defineProperty(exports, "Producer", { enumerable: true, get: function () { return producer_1.Producer; } });
8
8
  var message_1 = require("./src/message");
9
9
  Object.defineProperty(exports, "Message", { enumerable: true, get: function () { return message_1.Message; } });
10
- var redis_smq_monitor_1 = require("redis-smq-monitor");
11
- Object.defineProperty(exports, "MonitorServer", { enumerable: true, get: function () { return redis_smq_monitor_1.MonitorServer; } });
10
+ var monitor_server_1 = require("./src/monitor-server");
11
+ Object.defineProperty(exports, "MonitorServer", { enumerable: true, get: function () { return monitor_server_1.MonitorServer; } });
12
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,2CAA0C;AAAjC,oGAAA,QAAQ,OAAA;AACjB,2CAA0C;AAAjC,oGAAA,QAAQ,OAAA;AACjB,yCAAwC;AAA/B,kGAAA,OAAO,OAAA;AAChB,uDAAkD;AAAzC,kHAAA,aAAa,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,2CAA0C;AAAjC,oGAAA,QAAQ,OAAA;AACjB,2CAA0C;AAAjC,oGAAA,QAAQ,OAAA;AACjB,yCAAwC;AAA/B,kGAAA,OAAO,OAAA;AAChB,uDAAqD;AAA5C,+GAAA,aAAa,OAAA"}
@@ -1,36 +1,34 @@
1
- import { IConfig, IConsumerConstructorOptions, TCallback } from '../types';
1
+ import { IConfig, IConsumerConstructorOptions, ICallback, TUnaryFunction } from '../types';
2
2
  import { Instance } from './instance';
3
3
  import { Message } from './message';
4
4
  import { ConsumerStatsProvider } from './stats-provider/consumer-stats-provider';
5
- import { HeartBeat } from './heartbeat';
5
+ import { Heartbeat } from './heartbeat';
6
6
  import { GarbageCollector } from './gc';
7
+ import { SchedulerRunner } from './scheduler-runner';
8
+ import { RedisClient } from './redis-client';
7
9
  export declare abstract class Consumer extends Instance {
8
- protected readonly options: IConsumerConstructorOptions;
9
- protected readonly consumerMessageTTL: number;
10
- protected readonly consumerMessageConsumeTimeout: number;
11
- protected readonly messageRetryThreshold: number;
12
- protected readonly messageRetryDelay: number;
10
+ protected readonly options: Required<IConsumerConstructorOptions>;
11
+ protected schedulerRunnerInstance: SchedulerRunner | null;
13
12
  protected statsProvider: ConsumerStatsProvider | null;
14
13
  protected garbageCollectorInstance: GarbageCollector | null;
15
- protected heartBeatInstance: ReturnType<typeof HeartBeat> | null;
14
+ protected heartbeatInstance: Heartbeat | null;
16
15
  constructor(queueName: string, config?: IConfig, options?: IConsumerConstructorOptions);
17
16
  getConsumerMessageConsumeTimeout(): number;
18
17
  getMessageRetryThreshold(): number;
19
18
  getConsumerMessageTTL(): number;
20
19
  getMessageRetryDelay(): number;
21
- getOptions(): IConsumerConstructorOptions;
22
- protected getStatsProvider(): ConsumerStatsProvider;
20
+ getOptions(): Required<IConsumerConstructorOptions>;
21
+ getStatsProvider(): ConsumerStatsProvider;
23
22
  protected getNextMessage(): void;
24
23
  protected hasGoneUp(): boolean;
25
24
  protected hasGoneDown(): boolean;
26
25
  protected registerEventsHandlers(): void;
27
- protected setupHeartBeat(): void;
28
- protected setupGarbageCollector(): void;
29
- protected getGarbageCollectorInstance(): GarbageCollector;
30
- protected getHeartBeatInstance(): ReturnType<typeof HeartBeat>;
31
- protected setupQueues(): void;
32
- protected completeBootstrap(): void;
26
+ protected getGarbageCollectorInstance(cb: TUnaryFunction<GarbageCollector>): void;
27
+ protected getHeartBeatInstance(cb: TUnaryFunction<Heartbeat>): void;
28
+ protected getSchedulerRunnerInstance(cb: TUnaryFunction<SchedulerRunner>): void;
29
+ protected setupQueues(client: RedisClient, cb: ICallback<void>): void;
30
+ protected bootstrap(cb: ICallback<void>): void;
33
31
  protected handleConsume(msg: Message): void;
34
32
  protected handleConsumeFailure(msg: Message, error: Error): void;
35
- abstract consume(msg: Message, cb: TCallback<void>): void;
33
+ abstract consume(msg: Message, cb: ICallback<void>): void;
36
34
  }
@@ -7,32 +7,34 @@ const consumer_stats_provider_1 = require("./stats-provider/consumer-stats-provi
7
7
  const events_1 = require("./events");
8
8
  const heartbeat_1 = require("./heartbeat");
9
9
  const gc_1 = require("./gc");
10
- const consumer_redis_keys_1 = require("./redis-keys/consumer-redis-keys");
10
+ const scheduler_runner_1 = require("./scheduler-runner");
11
+ const queue_helpers_1 = require("./queue-helpers");
11
12
  class Consumer extends instance_1.Instance {
12
13
  constructor(queueName, config = {}, options = {}) {
13
- var _a, _b, _c, _d;
14
14
  super(queueName, config);
15
+ this.options = {
16
+ messageTTL: 0,
17
+ messageConsumeTimeout: 0,
18
+ messageRetryThreshold: 3,
19
+ messageRetryDelay: 60,
20
+ };
21
+ this.schedulerRunnerInstance = null;
15
22
  this.statsProvider = null;
16
23
  this.garbageCollectorInstance = null;
17
- this.heartBeatInstance = null;
18
- this.options = options;
19
- this.consumerMessageTTL = +((_a = options.messageTTL) !== null && _a !== void 0 ? _a : 0);
20
- this.consumerMessageConsumeTimeout = +((_b = options.messageConsumeTimeout) !== null && _b !== void 0 ? _b : 0);
21
- this.messageRetryThreshold = +((_c = options.messageRetryThreshold) !== null && _c !== void 0 ? _c : 3);
22
- this.messageRetryDelay = +((_d = options.messageRetryDelay) !== null && _d !== void 0 ? _d : 0);
23
- this.redisKeys = new consumer_redis_keys_1.ConsumerRedisKeys(this.getQueueName(), this.getId());
24
+ this.heartbeatInstance = null;
25
+ this.options = Object.assign(Object.assign({}, this.options), options);
24
26
  }
25
27
  getConsumerMessageConsumeTimeout() {
26
- return this.consumerMessageConsumeTimeout;
28
+ return this.options.messageConsumeTimeout;
27
29
  }
28
30
  getMessageRetryThreshold() {
29
- return this.messageRetryThreshold;
31
+ return this.options.messageRetryThreshold;
30
32
  }
31
33
  getConsumerMessageTTL() {
32
- return this.consumerMessageTTL;
34
+ return this.options.messageTTL;
33
35
  }
34
36
  getMessageRetryDelay() {
35
- return this.messageRetryDelay;
37
+ return this.options.messageRetryDelay;
36
38
  }
37
39
  getOptions() {
38
40
  return this.options;
@@ -45,54 +47,59 @@ class Consumer extends instance_1.Instance {
45
47
  }
46
48
  getNextMessage() {
47
49
  this.loggerInstance.info('Waiting for new messages...');
48
- const { keyQueue, keyConsumerProcessingQueue } = this.getInstanceRedisKeys();
49
- this.getRedisInstance().brpoplpush(keyQueue, keyConsumerProcessingQueue, 0, (err, json) => {
50
- if (err)
51
- this.error(err);
52
- else {
53
- if (!json) {
54
- throw new Error(`Expected a non-empty string`);
50
+ const { keyQueue, keyConsumerProcessingQueue } = this.redisKeys;
51
+ this.getRedisInstance((client) => {
52
+ client.brpoplpush(keyQueue, keyConsumerProcessingQueue, 0, (err, json) => {
53
+ if (err)
54
+ this.handleError(err);
55
+ else if (!json)
56
+ this.handleError(new Error('Expected a non empty string'));
57
+ else {
58
+ this.loggerInstance.info('Got new message...');
59
+ const message = message_1.Message.createFromMessage(json);
60
+ this.emit(events_1.events.MESSAGE_RECEIVED, message);
55
61
  }
56
- this.loggerInstance.info('Got new message...');
57
- const message = message_1.Message.createFromMessage(json);
58
- this.emit(events_1.events.MESSAGE_RECEIVED, message);
59
- }
62
+ });
60
63
  });
61
64
  }
62
65
  hasGoneUp() {
63
66
  return (super.hasGoneUp() &&
64
67
  this.startupFiredEvents.includes(events_1.events.GC_UP) &&
65
- this.startupFiredEvents.includes(events_1.events.HEARTBEAT_UP));
68
+ this.startupFiredEvents.includes(events_1.events.HEARTBEAT_UP) &&
69
+ this.startupFiredEvents.includes(events_1.events.SCHEDULER_RUNNER_UP));
66
70
  }
67
71
  hasGoneDown() {
68
72
  return (super.hasGoneDown() &&
69
73
  this.shutdownFiredEvents.includes(events_1.events.GC_DOWN) &&
70
- this.shutdownFiredEvents.includes(events_1.events.HEARTBEAT_DOWN));
74
+ this.shutdownFiredEvents.includes(events_1.events.HEARTBEAT_DOWN) &&
75
+ this.shutdownFiredEvents.includes(events_1.events.SCHEDULER_RUNNER_DOWN));
71
76
  }
72
77
  registerEventsHandlers() {
73
78
  super.registerEventsHandlers();
74
79
  this.on(events_1.events.HEARTBEAT_UP, () => this.handleStartupEvent(events_1.events.HEARTBEAT_UP));
75
- this.on(events_1.events.HEARTBEAT_DOWN, () => this.handleShutdownEvent(events_1.events.HEARTBEAT_DOWN));
80
+ this.on(events_1.events.HEARTBEAT_DOWN, () => {
81
+ this.heartbeatInstance = null;
82
+ this.handleShutdownEvent(events_1.events.HEARTBEAT_DOWN);
83
+ });
76
84
  this.on(events_1.events.GC_UP, () => this.handleStartupEvent(events_1.events.GC_UP));
77
- this.on(events_1.events.GC_DOWN, () => this.handleShutdownEvent(events_1.events.GC_DOWN));
78
- this.on(events_1.events.STATS_UP, () => {
79
- this.getStatsInstance().startAggregator();
85
+ this.on(events_1.events.GC_DOWN, () => {
86
+ this.garbageCollectorInstance = null;
87
+ this.handleShutdownEvent(events_1.events.GC_DOWN);
80
88
  });
81
- this.on(events_1.events.SCHEDULER_UP, () => {
82
- this.getScheduler().runTicker();
89
+ this.on(events_1.events.SCHEDULER_RUNNER_UP, () => this.handleStartupEvent(events_1.events.SCHEDULER_RUNNER_UP));
90
+ this.on(events_1.events.SCHEDULER_RUNNER_DOWN, () => {
91
+ this.schedulerRunnerInstance = null;
92
+ this.handleShutdownEvent(events_1.events.SCHEDULER_RUNNER_DOWN);
83
93
  });
84
94
  this.on(events_1.events.GOING_UP, () => {
85
- this.getHeartBeatInstance().start();
86
- this.getGarbageCollectorInstance().start();
95
+ this.getHeartBeatInstance((hb) => hb.start());
96
+ this.getGarbageCollectorInstance((gc) => gc.start());
97
+ this.getSchedulerRunnerInstance((sr) => sr.start());
87
98
  });
88
99
  this.on(events_1.events.GOING_DOWN, () => {
89
- this.getHeartBeatInstance().stop();
90
- this.getGarbageCollectorInstance().stop();
91
- });
92
- this.on(events_1.events.DOWN, () => {
93
- this.garbageCollectorInstance = null;
94
- this.heartBeatInstance = null;
95
- this.statsProvider = null;
100
+ this.getHeartBeatInstance((hb) => hb.stop());
101
+ this.getGarbageCollectorInstance((gc) => gc.stop());
102
+ this.getSchedulerRunnerInstance((sr) => sr.stop());
96
103
  });
97
104
  this.on(events_1.events.UP, () => {
98
105
  this.emit(events_1.events.MESSAGE_NEXT);
@@ -103,26 +110,32 @@ class Consumer extends instance_1.Instance {
103
110
  }
104
111
  });
105
112
  this.on(events_1.events.MESSAGE_RECEIVED, (message) => {
106
- const messageCollector = this.getGarbageCollectorInstance().getMessageCollector();
107
113
  if (this.powerManager.isRunning()) {
108
- if (this.statsProvider)
109
- this.statsProvider.incrementProcessingSlot();
110
- if (messageCollector.hasMessageExpired(message)) {
111
- this.emit(events_1.events.MESSAGE_EXPIRED, message);
112
- }
113
- else
114
- this.handleConsume(message);
114
+ this.getGarbageCollectorInstance((gc) => {
115
+ gc.getMessageCollector((messageCollector) => {
116
+ if (this.statsProvider)
117
+ this.statsProvider.incrementProcessingSlot();
118
+ if (messageCollector.hasMessageExpired(message)) {
119
+ this.emit(events_1.events.MESSAGE_EXPIRED, message);
120
+ }
121
+ else
122
+ this.handleConsume(message);
123
+ });
124
+ });
115
125
  }
116
126
  });
117
127
  this.on(events_1.events.MESSAGE_EXPIRED, (message) => {
118
128
  this.loggerInstance.info(`Message [${message.getId()}] has expired`);
119
129
  const { keyConsumerProcessingQueue } = this.getInstanceRedisKeys();
120
- const messageCollector = this.getGarbageCollectorInstance().getMessageCollector();
121
- messageCollector.collectExpiredMessage(message, keyConsumerProcessingQueue, () => {
122
- if (this.statsProvider)
123
- this.statsProvider.incrementAcknowledgedSlot();
124
- this.loggerInstance.info(`Message [${message.getId()}] successfully processed`);
125
- this.emit(events_1.events.MESSAGE_NEXT);
130
+ this.getGarbageCollectorInstance((gc) => {
131
+ gc.getMessageCollector((messageCollector) => {
132
+ messageCollector.collectExpiredMessage(message, keyConsumerProcessingQueue, () => {
133
+ if (this.statsProvider)
134
+ this.statsProvider.incrementAcknowledgedSlot();
135
+ this.loggerInstance.info(`Message [${message.getId()}] successfully processed`);
136
+ this.emit(events_1.events.MESSAGE_NEXT);
137
+ });
138
+ });
126
139
  });
127
140
  });
128
141
  this.on(events_1.events.MESSAGE_ACKNOWLEDGED, () => {
@@ -134,52 +147,59 @@ class Consumer extends instance_1.Instance {
134
147
  if (this.statsProvider)
135
148
  this.statsProvider.incrementUnacknowledgedSlot();
136
149
  const keys = this.getInstanceRedisKeys();
137
- const messageCollector = this.getGarbageCollectorInstance().getMessageCollector();
138
- messageCollector.collectMessage(msg, keys.keyConsumerProcessingQueue, (err) => {
139
- if (err)
140
- this.error(err);
141
- else
142
- this.emit(events_1.events.MESSAGE_NEXT);
150
+ this.getGarbageCollectorInstance((gc) => {
151
+ gc.getMessageCollector((messageCollector) => {
152
+ messageCollector.collectMessage(msg, keys.keyConsumerProcessingQueue, (err) => {
153
+ if (err)
154
+ this.handleError(err);
155
+ else
156
+ this.emit(events_1.events.MESSAGE_NEXT);
157
+ });
158
+ });
143
159
  });
144
160
  });
145
161
  this.on(events_1.events.MESSAGE_CONSUME_TIMEOUT, (message) => {
146
162
  this.handleConsumeFailure(message, new Error(`Consumer timed out after [${this.getConsumerMessageConsumeTimeout()}]`));
147
163
  });
148
164
  }
149
- setupHeartBeat() {
150
- this.heartBeatInstance = (0, heartbeat_1.HeartBeat)(this);
165
+ getGarbageCollectorInstance(cb) {
166
+ if (!this.garbageCollectorInstance)
167
+ this.emit(events_1.events.ERROR, new Error(`Expected an instance of GarbageCollector`));
168
+ else
169
+ cb(this.garbageCollectorInstance);
151
170
  }
152
- setupGarbageCollector() {
153
- this.garbageCollectorInstance = new gc_1.GarbageCollector(this);
171
+ getHeartBeatInstance(cb) {
172
+ if (!this.heartbeatInstance)
173
+ this.emit(events_1.events.ERROR, new Error(`Expected an instance of HeartBeat`));
174
+ else
175
+ cb(this.heartbeatInstance);
154
176
  }
155
- getGarbageCollectorInstance() {
156
- if (!this.garbageCollectorInstance) {
157
- throw new Error(`Expected an instance of GarbageCollector`);
158
- }
159
- return this.garbageCollectorInstance;
177
+ getSchedulerRunnerInstance(cb) {
178
+ if (!this.schedulerRunnerInstance)
179
+ this.emit(events_1.events.ERROR, new Error('Expected instance of SchedulerRunner'));
180
+ else
181
+ cb(this.schedulerRunnerInstance);
160
182
  }
161
- getHeartBeatInstance() {
162
- if (!this.heartBeatInstance) {
163
- throw new Error(`Expected an instance of HeartBeat`);
164
- }
165
- return this.heartBeatInstance;
166
- }
167
- setupQueues() {
168
- const { keyConsumerProcessingQueue, keyIndexQueueProcessing, keyIndexQueueQueuesProcessing, } = this.getInstanceRedisKeys();
169
- const multi = this.getRedisInstance().multi();
170
- multi.hset(keyIndexQueueQueuesProcessing, keyConsumerProcessingQueue, this.getId());
171
- multi.sadd(keyIndexQueueProcessing, keyConsumerProcessingQueue);
172
- this.getRedisInstance().execMulti(multi, (err) => {
183
+ setupQueues(client, cb) {
184
+ super.setupQueues(client, (err) => {
173
185
  if (err)
174
- this.error(err);
175
- else
176
- super.setupQueues();
186
+ cb(err);
187
+ else {
188
+ queue_helpers_1.queueHelpers.setupConsumerQueues(client, this.getQueueName(), this.getId(), cb);
189
+ }
177
190
  });
178
191
  }
179
- completeBootstrap() {
180
- this.setupHeartBeat();
181
- this.setupGarbageCollector();
182
- super.completeBootstrap();
192
+ bootstrap(cb) {
193
+ super.bootstrap((err) => {
194
+ if (err)
195
+ cb(err);
196
+ else {
197
+ this.heartbeatInstance = new heartbeat_1.Heartbeat(this);
198
+ this.garbageCollectorInstance = new gc_1.GarbageCollector(this);
199
+ this.schedulerRunnerInstance = new scheduler_runner_1.SchedulerRunner(this);
200
+ cb();
201
+ }
202
+ });
183
203
  }
184
204
  handleConsume(msg) {
185
205
  let isTimeout = false;
@@ -199,13 +219,15 @@ class Consumer extends instance_1.Instance {
199
219
  }, consumeTimeout);
200
220
  }
201
221
  const acknowledgeMessage = () => {
202
- this.getRedisInstance().rpop(keys.keyConsumerProcessingQueue, (err) => {
203
- if (err)
204
- this.error(err);
205
- else {
206
- this.loggerInstance.info(`Message [${msg.getId()}] successfully processed`);
207
- this.emit(events_1.events.MESSAGE_ACKNOWLEDGED, msg);
208
- }
222
+ this.getRedisInstance((client) => {
223
+ client.rpop(keys.keyConsumerProcessingQueue, (err) => {
224
+ if (err)
225
+ this.handleError(err);
226
+ else {
227
+ this.loggerInstance.info(`Message [${msg.getId()}] successfully processed`);
228
+ this.emit(events_1.events.MESSAGE_ACKNOWLEDGED, msg);
229
+ }
230
+ });
209
231
  });
210
232
  };
211
233
  const onConsumed = (err) => {