@deenruv/job-queue-plugin 1.0.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.
- package/LICENSE +23 -0
- package/README.md +94 -0
- package/package/bullmq/bullmq-job-queue-strategy.d.ts +39 -0
- package/package/bullmq/bullmq-job-queue-strategy.js +362 -0
- package/package/bullmq/bullmq-job-queue-strategy.js.map +1 -0
- package/package/bullmq/constants.d.ts +4 -0
- package/package/bullmq/constants.js +16 -0
- package/package/bullmq/constants.js.map +1 -0
- package/package/bullmq/index.d.ts +2 -0
- package/package/bullmq/index.js +27 -0
- package/package/bullmq/index.js.map +1 -0
- package/package/bullmq/plugin.d.ts +133 -0
- package/package/bullmq/plugin.js +171 -0
- package/package/bullmq/plugin.js.map +1 -0
- package/package/bullmq/redis-health-check-strategy.d.ts +6 -0
- package/package/bullmq/redis-health-check-strategy.js +15 -0
- package/package/bullmq/redis-health-check-strategy.js.map +1 -0
- package/package/bullmq/redis-health-indicator.d.ts +8 -0
- package/package/bullmq/redis-health-indicator.js +80 -0
- package/package/bullmq/redis-health-indicator.js.map +1 -0
- package/package/bullmq/redis-job-buffer-storage-strategy.d.ts +16 -0
- package/package/bullmq/redis-job-buffer-storage-strategy.js +82 -0
- package/package/bullmq/redis-job-buffer-storage-strategy.js.map +1 -0
- package/package/bullmq/scripts/get-jobs-by-type.d.ts +10 -0
- package/package/bullmq/scripts/get-jobs-by-type.js +114 -0
- package/package/bullmq/scripts/get-jobs-by-type.js.map +1 -0
- package/package/bullmq/types.d.ts +101 -0
- package/package/bullmq/types.js +3 -0
- package/package/bullmq/types.js.map +1 -0
- package/package/index.d.ts +4 -0
- package/package/index.js +8 -0
- package/package/index.js.map +1 -0
- package/package/pub-sub/constants.d.ts +2 -0
- package/package/pub-sub/constants.js +6 -0
- package/package/pub-sub/constants.js.map +1 -0
- package/package/pub-sub/index.d.ts +2 -0
- package/package/pub-sub/index.js +19 -0
- package/package/pub-sub/index.js.map +1 -0
- package/package/pub-sub/options.d.ts +13 -0
- package/package/pub-sub/options.js +3 -0
- package/package/pub-sub/options.js.map +1 -0
- package/package/pub-sub/plugin.d.ts +6 -0
- package/package/pub-sub/plugin.js +36 -0
- package/package/pub-sub/plugin.js.map +1 -0
- package/package/pub-sub/pub-sub-job-queue-strategy.d.ts +16 -0
- package/package/pub-sub/pub-sub-job-queue-strategy.js +123 -0
- package/package/pub-sub/pub-sub-job-queue-strategy.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { BullMQPluginOptions } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* @description
|
|
4
|
+
* This plugin is a drop-in replacement of the DefaultJobQueuePlugin, which implements a push-based
|
|
5
|
+
* job queue strategy built on top of the popular [BullMQ](https://github.com/taskforcesh/bullmq) library.
|
|
6
|
+
*
|
|
7
|
+
* ## Advantages over the DefaultJobQueuePlugin
|
|
8
|
+
*
|
|
9
|
+
* The advantage of this approach is that jobs are stored in Redis rather than in the database. For more complex
|
|
10
|
+
* applications with many job queues and/or multiple worker instances, this can massively reduce the load on the
|
|
11
|
+
* DB server. The reason for this is that the DefaultJobQueuePlugin uses polling to check for new jobs. By default
|
|
12
|
+
* it will poll every 200ms. A typical Deenruv instance uses at least 3 queues (handling emails, collections, search index),
|
|
13
|
+
* so even with a single worker instance this results in 15 queries per second to the DB constantly. Adding more
|
|
14
|
+
* custom queues and multiple worker instances can easily result in 50 or 100 queries per second. At this point
|
|
15
|
+
* performance may be impacted.
|
|
16
|
+
*
|
|
17
|
+
* Using this plugin, no polling is needed, as BullMQ will _push_ jobs to the worker(s) as and when they are added
|
|
18
|
+
* to the queue. This results in significantly more scalable performance characteristics, as well as lower latency
|
|
19
|
+
* in processing jobs.
|
|
20
|
+
*
|
|
21
|
+
* ## Installation
|
|
22
|
+
*
|
|
23
|
+
* `yarn add \@deenruv/job-queue-plugin bullmq`
|
|
24
|
+
*
|
|
25
|
+
* or
|
|
26
|
+
*
|
|
27
|
+
* `npm install \@deenruv/job-queue-plugin bullmq`
|
|
28
|
+
*
|
|
29
|
+
* **Note:** The v1.x version of this plugin is designed to work with bullmq v1.x, etc.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { BullMQJobQueuePlugin } from '\@deenruv/job-queue-plugin/package/bullmq';
|
|
34
|
+
*
|
|
35
|
+
* const config: DeenruvConfig = {
|
|
36
|
+
* // Add an instance of the plugin to the plugins array
|
|
37
|
+
* plugins: [
|
|
38
|
+
* // DefaultJobQueuePlugin should be removed from the plugins array
|
|
39
|
+
* BullMQJobQueuePlugin.init({
|
|
40
|
+
* connection: {
|
|
41
|
+
* port: 6379
|
|
42
|
+
* }
|
|
43
|
+
* }),
|
|
44
|
+
* ],
|
|
45
|
+
* };
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* ### Running Redis locally
|
|
49
|
+
*
|
|
50
|
+
* To develop with this plugin, you'll need an instance of Redis to connect to. Here's a docker-compose config
|
|
51
|
+
* that will set up [Redis](https://redis.io/) as well as [Redis Commander](https://github.com/joeferner/redis-commander),
|
|
52
|
+
* which is a web-based UI for interacting with Redis:
|
|
53
|
+
*
|
|
54
|
+
* ```YAML
|
|
55
|
+
* version: "3"
|
|
56
|
+
* services:
|
|
57
|
+
* redis:
|
|
58
|
+
* image: bitnami/redis:6.2
|
|
59
|
+
* hostname: redis
|
|
60
|
+
* container_name: redis
|
|
61
|
+
* environment:
|
|
62
|
+
* - ALLOW_EMPTY_PASSWORD=yes
|
|
63
|
+
* ports:
|
|
64
|
+
* - "6379:6379"
|
|
65
|
+
* redis-commander:
|
|
66
|
+
* container_name: redis-commander
|
|
67
|
+
* hostname: redis-commander
|
|
68
|
+
* image: rediscommander/redis-commander:latest
|
|
69
|
+
* environment:
|
|
70
|
+
* - REDIS_HOSTS=local:redis:6379
|
|
71
|
+
* ports:
|
|
72
|
+
* - "8085:8081"
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* ## Concurrency
|
|
76
|
+
*
|
|
77
|
+
* The default concurrency of a single worker is 3, i.e. up to 3 jobs will be processed at the same time.
|
|
78
|
+
* You can change the concurrency in the `workerOptions` passed to the `init()` method:
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const config: DeenruvConfig = {
|
|
83
|
+
* plugins: [
|
|
84
|
+
* BullMQJobQueuePlugin.init({
|
|
85
|
+
* workerOptions: {
|
|
86
|
+
* concurrency: 10,
|
|
87
|
+
* },
|
|
88
|
+
* }),
|
|
89
|
+
* ],
|
|
90
|
+
* };
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* ## Removing old jobs
|
|
94
|
+
*
|
|
95
|
+
* By default, BullMQ will keep completed jobs in the `completed` set and failed jobs in the `failed` set. Over time,
|
|
96
|
+
* these sets can grow very large. Since Deenruv v2.1, the default behaviour is to remove jobs from these sets after
|
|
97
|
+
* 30 days or after a maximum of 5,000 completed or failed jobs.
|
|
98
|
+
*
|
|
99
|
+
* This can be configured using the `removeOnComplete` and `removeOnFail` options:
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* const config: DeenruvConfig = {
|
|
104
|
+
* plugins: [
|
|
105
|
+
* BullMQJobQueuePlugin.init({
|
|
106
|
+
* workerOptions: {
|
|
107
|
+
* removeOnComplete: {
|
|
108
|
+
* count: 500,
|
|
109
|
+
* },
|
|
110
|
+
* removeOnFail: {
|
|
111
|
+
* age: 60 * 60 * 24 * 7, // 7 days
|
|
112
|
+
* count: 1000,
|
|
113
|
+
* },
|
|
114
|
+
* }
|
|
115
|
+
* }),
|
|
116
|
+
* ],
|
|
117
|
+
* };
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* The `count` option specifies the maximum number of jobs to keep in the set, while the `age` option specifies the
|
|
121
|
+
* maximum age of a job in seconds. If both options are specified, then the jobs kept will be the ones that satisfy
|
|
122
|
+
* both properties.
|
|
123
|
+
*
|
|
124
|
+
* @docsCategory core plugins/JobQueuePlugin
|
|
125
|
+
*/
|
|
126
|
+
export declare class BullMQJobQueuePlugin {
|
|
127
|
+
static options: BullMQPluginOptions;
|
|
128
|
+
/**
|
|
129
|
+
* @description
|
|
130
|
+
* Configures the plugin.
|
|
131
|
+
*/
|
|
132
|
+
static init(options: BullMQPluginOptions): typeof BullMQJobQueuePlugin;
|
|
133
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.BullMQJobQueuePlugin = void 0;
|
|
10
|
+
const core_1 = require("@deenruv/core");
|
|
11
|
+
const bullmq_job_queue_strategy_1 = require("./bullmq-job-queue-strategy");
|
|
12
|
+
const constants_1 = require("./constants");
|
|
13
|
+
const redis_health_check_strategy_1 = require("./redis-health-check-strategy");
|
|
14
|
+
const redis_health_indicator_1 = require("./redis-health-indicator");
|
|
15
|
+
const redis_job_buffer_storage_strategy_1 = require("./redis-job-buffer-storage-strategy");
|
|
16
|
+
/**
|
|
17
|
+
* @description
|
|
18
|
+
* This plugin is a drop-in replacement of the DefaultJobQueuePlugin, which implements a push-based
|
|
19
|
+
* job queue strategy built on top of the popular [BullMQ](https://github.com/taskforcesh/bullmq) library.
|
|
20
|
+
*
|
|
21
|
+
* ## Advantages over the DefaultJobQueuePlugin
|
|
22
|
+
*
|
|
23
|
+
* The advantage of this approach is that jobs are stored in Redis rather than in the database. For more complex
|
|
24
|
+
* applications with many job queues and/or multiple worker instances, this can massively reduce the load on the
|
|
25
|
+
* DB server. The reason for this is that the DefaultJobQueuePlugin uses polling to check for new jobs. By default
|
|
26
|
+
* it will poll every 200ms. A typical Deenruv instance uses at least 3 queues (handling emails, collections, search index),
|
|
27
|
+
* so even with a single worker instance this results in 15 queries per second to the DB constantly. Adding more
|
|
28
|
+
* custom queues and multiple worker instances can easily result in 50 or 100 queries per second. At this point
|
|
29
|
+
* performance may be impacted.
|
|
30
|
+
*
|
|
31
|
+
* Using this plugin, no polling is needed, as BullMQ will _push_ jobs to the worker(s) as and when they are added
|
|
32
|
+
* to the queue. This results in significantly more scalable performance characteristics, as well as lower latency
|
|
33
|
+
* in processing jobs.
|
|
34
|
+
*
|
|
35
|
+
* ## Installation
|
|
36
|
+
*
|
|
37
|
+
* `yarn add \@deenruv/job-queue-plugin bullmq`
|
|
38
|
+
*
|
|
39
|
+
* or
|
|
40
|
+
*
|
|
41
|
+
* `npm install \@deenruv/job-queue-plugin bullmq`
|
|
42
|
+
*
|
|
43
|
+
* **Note:** The v1.x version of this plugin is designed to work with bullmq v1.x, etc.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { BullMQJobQueuePlugin } from '\@deenruv/job-queue-plugin/package/bullmq';
|
|
48
|
+
*
|
|
49
|
+
* const config: DeenruvConfig = {
|
|
50
|
+
* // Add an instance of the plugin to the plugins array
|
|
51
|
+
* plugins: [
|
|
52
|
+
* // DefaultJobQueuePlugin should be removed from the plugins array
|
|
53
|
+
* BullMQJobQueuePlugin.init({
|
|
54
|
+
* connection: {
|
|
55
|
+
* port: 6379
|
|
56
|
+
* }
|
|
57
|
+
* }),
|
|
58
|
+
* ],
|
|
59
|
+
* };
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* ### Running Redis locally
|
|
63
|
+
*
|
|
64
|
+
* To develop with this plugin, you'll need an instance of Redis to connect to. Here's a docker-compose config
|
|
65
|
+
* that will set up [Redis](https://redis.io/) as well as [Redis Commander](https://github.com/joeferner/redis-commander),
|
|
66
|
+
* which is a web-based UI for interacting with Redis:
|
|
67
|
+
*
|
|
68
|
+
* ```YAML
|
|
69
|
+
* version: "3"
|
|
70
|
+
* services:
|
|
71
|
+
* redis:
|
|
72
|
+
* image: bitnami/redis:6.2
|
|
73
|
+
* hostname: redis
|
|
74
|
+
* container_name: redis
|
|
75
|
+
* environment:
|
|
76
|
+
* - ALLOW_EMPTY_PASSWORD=yes
|
|
77
|
+
* ports:
|
|
78
|
+
* - "6379:6379"
|
|
79
|
+
* redis-commander:
|
|
80
|
+
* container_name: redis-commander
|
|
81
|
+
* hostname: redis-commander
|
|
82
|
+
* image: rediscommander/redis-commander:latest
|
|
83
|
+
* environment:
|
|
84
|
+
* - REDIS_HOSTS=local:redis:6379
|
|
85
|
+
* ports:
|
|
86
|
+
* - "8085:8081"
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* ## Concurrency
|
|
90
|
+
*
|
|
91
|
+
* The default concurrency of a single worker is 3, i.e. up to 3 jobs will be processed at the same time.
|
|
92
|
+
* You can change the concurrency in the `workerOptions` passed to the `init()` method:
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const config: DeenruvConfig = {
|
|
97
|
+
* plugins: [
|
|
98
|
+
* BullMQJobQueuePlugin.init({
|
|
99
|
+
* workerOptions: {
|
|
100
|
+
* concurrency: 10,
|
|
101
|
+
* },
|
|
102
|
+
* }),
|
|
103
|
+
* ],
|
|
104
|
+
* };
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* ## Removing old jobs
|
|
108
|
+
*
|
|
109
|
+
* By default, BullMQ will keep completed jobs in the `completed` set and failed jobs in the `failed` set. Over time,
|
|
110
|
+
* these sets can grow very large. Since Deenruv v2.1, the default behaviour is to remove jobs from these sets after
|
|
111
|
+
* 30 days or after a maximum of 5,000 completed or failed jobs.
|
|
112
|
+
*
|
|
113
|
+
* This can be configured using the `removeOnComplete` and `removeOnFail` options:
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const config: DeenruvConfig = {
|
|
118
|
+
* plugins: [
|
|
119
|
+
* BullMQJobQueuePlugin.init({
|
|
120
|
+
* workerOptions: {
|
|
121
|
+
* removeOnComplete: {
|
|
122
|
+
* count: 500,
|
|
123
|
+
* },
|
|
124
|
+
* removeOnFail: {
|
|
125
|
+
* age: 60 * 60 * 24 * 7, // 7 days
|
|
126
|
+
* count: 1000,
|
|
127
|
+
* },
|
|
128
|
+
* }
|
|
129
|
+
* }),
|
|
130
|
+
* ],
|
|
131
|
+
* };
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* The `count` option specifies the maximum number of jobs to keep in the set, while the `age` option specifies the
|
|
135
|
+
* maximum age of a job in seconds. If both options are specified, then the jobs kept will be the ones that satisfy
|
|
136
|
+
* both properties.
|
|
137
|
+
*
|
|
138
|
+
* @docsCategory core plugins/JobQueuePlugin
|
|
139
|
+
*/
|
|
140
|
+
let BullMQJobQueuePlugin = class BullMQJobQueuePlugin {
|
|
141
|
+
/**
|
|
142
|
+
* @description
|
|
143
|
+
* Configures the plugin.
|
|
144
|
+
*/
|
|
145
|
+
static init(options) {
|
|
146
|
+
this.options = options;
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
exports.BullMQJobQueuePlugin = BullMQJobQueuePlugin;
|
|
151
|
+
exports.BullMQJobQueuePlugin = BullMQJobQueuePlugin = __decorate([
|
|
152
|
+
(0, core_1.DeenruvPlugin)({
|
|
153
|
+
imports: [core_1.PluginCommonModule],
|
|
154
|
+
configuration: (config) => {
|
|
155
|
+
config.jobQueueOptions.jobQueueStrategy = new bullmq_job_queue_strategy_1.BullMQJobQueueStrategy();
|
|
156
|
+
config.jobQueueOptions.jobBufferStorageStrategy =
|
|
157
|
+
new redis_job_buffer_storage_strategy_1.RedisJobBufferStorageStrategy();
|
|
158
|
+
config.systemOptions.healthChecks.push(new redis_health_check_strategy_1.RedisHealthCheckStrategy());
|
|
159
|
+
return config;
|
|
160
|
+
},
|
|
161
|
+
providers: [
|
|
162
|
+
{
|
|
163
|
+
provide: constants_1.BULLMQ_PLUGIN_OPTIONS,
|
|
164
|
+
useFactory: () => BullMQJobQueuePlugin.options,
|
|
165
|
+
},
|
|
166
|
+
redis_health_indicator_1.RedisHealthIndicator,
|
|
167
|
+
],
|
|
168
|
+
compatibility: "^0.0.0",
|
|
169
|
+
})
|
|
170
|
+
], BullMQJobQueuePlugin);
|
|
171
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/bullmq/plugin.ts"],"names":[],"mappings":";;;;;;;;;AAAA,wCAAkE;AAElE,2EAAqE;AACrE,2CAAoD;AACpD,+EAAyE;AACzE,qEAAgE;AAChE,2FAAoF;AAGpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2HG;AAmBI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAG/B;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,OAA4B;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAXY,oDAAoB;+BAApB,oBAAoB;IAlBhC,IAAA,oBAAa,EAAC;QACb,OAAO,EAAE,CAAC,yBAAkB,CAAC;QAC7B,aAAa,EAAE,CAAC,MAAM,EAAE,EAAE;YACxB,MAAM,CAAC,eAAe,CAAC,gBAAgB,GAAG,IAAI,kDAAsB,EAAE,CAAC;YACvE,MAAM,CAAC,eAAe,CAAC,wBAAwB;gBAC7C,IAAI,iEAA6B,EAAE,CAAC;YACtC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,sDAAwB,EAAE,CAAC,CAAC;YACvE,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,SAAS,EAAE;YACT;gBACE,OAAO,EAAE,iCAAqB;gBAC9B,UAAU,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO;aAC/C;YACD,6CAAoB;SACrB;QACD,aAAa,EAAE,QAAQ;KACxB,CAAC;GACW,oBAAoB,CAWhC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { HealthIndicatorFunction } from "@nestjs/terminus";
|
|
2
|
+
import { HealthCheckStrategy, Injector } from "@deenruv/core";
|
|
3
|
+
export declare class RedisHealthCheckStrategy implements HealthCheckStrategy {
|
|
4
|
+
init(injector: Injector): void;
|
|
5
|
+
getHealthIndicator(): HealthIndicatorFunction;
|
|
6
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisHealthCheckStrategy = void 0;
|
|
4
|
+
const redis_health_indicator_1 = require("./redis-health-indicator");
|
|
5
|
+
let indicator;
|
|
6
|
+
class RedisHealthCheckStrategy {
|
|
7
|
+
init(injector) {
|
|
8
|
+
indicator = injector.get(redis_health_indicator_1.RedisHealthIndicator);
|
|
9
|
+
}
|
|
10
|
+
getHealthIndicator() {
|
|
11
|
+
return () => indicator.isHealthy("redis (job queue)");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.RedisHealthCheckStrategy = RedisHealthCheckStrategy;
|
|
15
|
+
//# sourceMappingURL=redis-health-check-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-health-check-strategy.js","sourceRoot":"","sources":["../../src/bullmq/redis-health-check-strategy.ts"],"names":[],"mappings":";;;AAGA,qEAAgE;AAEhE,IAAI,SAA+B,CAAC;AAEpC,MAAa,wBAAwB;IACnC,IAAI,CAAC,QAAkB;QACrB,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,6CAAoB,CAAC,CAAC;IACjD,CAAC;IACD,kBAAkB;QAChB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACxD,CAAC;CACF;AAPD,4DAOC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { HealthIndicator, HealthIndicatorResult } from "@nestjs/terminus";
|
|
2
|
+
import { BullMQPluginOptions } from "./types";
|
|
3
|
+
export declare class RedisHealthIndicator extends HealthIndicator {
|
|
4
|
+
private options;
|
|
5
|
+
private timeoutTimer;
|
|
6
|
+
constructor(options: BullMQPluginOptions);
|
|
7
|
+
isHealthy(key: string, timeoutMs?: number): Promise<HealthIndicatorResult>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.RedisHealthIndicator = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const terminus_1 = require("@nestjs/terminus");
|
|
18
|
+
const core_1 = require("@deenruv/core");
|
|
19
|
+
const bullmq_1 = require("bullmq");
|
|
20
|
+
const constants_1 = require("./constants");
|
|
21
|
+
let RedisHealthIndicator = class RedisHealthIndicator extends terminus_1.HealthIndicator {
|
|
22
|
+
constructor(options) {
|
|
23
|
+
super();
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
async isHealthy(key, timeoutMs = 5000) {
|
|
27
|
+
if (!this.options.connection) {
|
|
28
|
+
throw new Error("Redis connection options are not defined");
|
|
29
|
+
}
|
|
30
|
+
const connection = new bullmq_1.RedisConnection(this.options.connection);
|
|
31
|
+
const pingResult = await new Promise(async (resolve, reject) => {
|
|
32
|
+
try {
|
|
33
|
+
connection.on("error", (err) => {
|
|
34
|
+
core_1.Logger.error(`Redis health check error: ${JSON.stringify(err.message)}`, constants_1.loggerCtx, err.stack);
|
|
35
|
+
resolve(err);
|
|
36
|
+
});
|
|
37
|
+
if (this.timeoutTimer) {
|
|
38
|
+
clearTimeout(this.timeoutTimer);
|
|
39
|
+
}
|
|
40
|
+
const timeout = new Promise((_resolve) => (this.timeoutTimer = setTimeout(_resolve, timeoutMs)));
|
|
41
|
+
const client = await Promise.race([connection.client, timeout]);
|
|
42
|
+
clearTimeout(this.timeoutTimer);
|
|
43
|
+
if (!client) {
|
|
44
|
+
resolve("timeout");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
void client.ping((err, res) => {
|
|
48
|
+
if (err) {
|
|
49
|
+
resolve(err);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
resolve(res);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
resolve(e);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
try {
|
|
61
|
+
await connection.close();
|
|
62
|
+
// await connection.disconnect();
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
core_1.Logger.error(`Redis health check error closing connection: ${JSON.stringify(e.message)}`, constants_1.loggerCtx, e.stack);
|
|
66
|
+
}
|
|
67
|
+
const result = this.getStatus(key, pingResult === "PONG");
|
|
68
|
+
if (pingResult === "PONG") {
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
throw new terminus_1.HealthCheckError("Redis failed", result);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
exports.RedisHealthIndicator = RedisHealthIndicator;
|
|
75
|
+
exports.RedisHealthIndicator = RedisHealthIndicator = __decorate([
|
|
76
|
+
(0, common_1.Injectable)(),
|
|
77
|
+
__param(0, (0, common_1.Inject)(constants_1.BULLMQ_PLUGIN_OPTIONS)),
|
|
78
|
+
__metadata("design:paramtypes", [Object])
|
|
79
|
+
], RedisHealthIndicator);
|
|
80
|
+
//# sourceMappingURL=redis-health-indicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-health-indicator.js","sourceRoot":"","sources":["../../src/bullmq/redis-health-indicator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Injector, Job, JobBufferStorageStrategy } from "@deenruv/core";
|
|
2
|
+
export declare class RedisJobBufferStorageStrategy implements JobBufferStorageStrategy {
|
|
3
|
+
private redis;
|
|
4
|
+
init(injector: Injector): void;
|
|
5
|
+
add(bufferId: string, job: Job<any>): Promise<Job<any>>;
|
|
6
|
+
bufferSize(bufferIds?: string[]): Promise<{
|
|
7
|
+
[bufferId: string]: number;
|
|
8
|
+
}>;
|
|
9
|
+
flush(bufferIds?: string[]): Promise<{
|
|
10
|
+
[bufferId: string]: Job[];
|
|
11
|
+
}>;
|
|
12
|
+
private keyName;
|
|
13
|
+
private toJobConfigString;
|
|
14
|
+
private toJob;
|
|
15
|
+
private getAllBufferIds;
|
|
16
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisJobBufferStorageStrategy = void 0;
|
|
4
|
+
const core_1 = require("@deenruv/core");
|
|
5
|
+
const ioredis_1 = require("ioredis");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
const BUFFER_LIST_PREFIX = "deenruv-job-buffer";
|
|
8
|
+
class RedisJobBufferStorageStrategy {
|
|
9
|
+
init(injector) {
|
|
10
|
+
const options = injector.get(constants_1.BULLMQ_PLUGIN_OPTIONS);
|
|
11
|
+
if (options.connection instanceof ioredis_1.Redis) {
|
|
12
|
+
this.redis = options.connection;
|
|
13
|
+
}
|
|
14
|
+
else if (options.connection instanceof ioredis_1.Cluster) {
|
|
15
|
+
this.redis = options.connection;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.redis = new ioredis_1.Redis(options.connection);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async add(bufferId, job) {
|
|
22
|
+
const result = await this.redis.lpush(this.keyName(bufferId), this.toJobConfigString(job));
|
|
23
|
+
return job;
|
|
24
|
+
}
|
|
25
|
+
async bufferSize(bufferIds) {
|
|
26
|
+
const ids = (bufferIds === null || bufferIds === void 0 ? void 0 : bufferIds.length) ? bufferIds : await this.getAllBufferIds();
|
|
27
|
+
const result = {};
|
|
28
|
+
for (const id of bufferIds || []) {
|
|
29
|
+
const key = this.keyName(id);
|
|
30
|
+
const count = await this.redis.llen(key);
|
|
31
|
+
result[id] = count;
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
async flush(bufferIds) {
|
|
36
|
+
const ids = (bufferIds === null || bufferIds === void 0 ? void 0 : bufferIds.length) ? bufferIds : await this.getAllBufferIds();
|
|
37
|
+
const result = {};
|
|
38
|
+
for (const id of bufferIds || []) {
|
|
39
|
+
const key = this.keyName(id);
|
|
40
|
+
const items = await this.redis.lrange(key, 0, -1);
|
|
41
|
+
await this.redis.del(key);
|
|
42
|
+
result[id] = items.map((item) => this.toJob(item));
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
keyName(bufferId) {
|
|
47
|
+
return `${BUFFER_LIST_PREFIX}:${bufferId}`;
|
|
48
|
+
}
|
|
49
|
+
toJobConfigString(job) {
|
|
50
|
+
var _a;
|
|
51
|
+
const jobConfig = Object.assign(Object.assign({}, job), { data: job.data, id: (_a = job.id) !== null && _a !== void 0 ? _a : undefined });
|
|
52
|
+
return JSON.stringify(jobConfig);
|
|
53
|
+
}
|
|
54
|
+
toJob(jobConfigString) {
|
|
55
|
+
try {
|
|
56
|
+
const jobConfig = JSON.parse(jobConfigString);
|
|
57
|
+
return new core_1.Job(jobConfig);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
core_1.Logger.error(`Could not parse buffered job:\n${JSON.stringify(e.message)}`, constants_1.loggerCtx, e.stack);
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async getAllBufferIds() {
|
|
65
|
+
const stream = this.redis instanceof ioredis_1.Redis
|
|
66
|
+
? this.redis.scanStream({
|
|
67
|
+
match: `${BUFFER_LIST_PREFIX}:*`,
|
|
68
|
+
})
|
|
69
|
+
: this.redis.nodes()[0].scanStream({
|
|
70
|
+
match: `${BUFFER_LIST_PREFIX}:*`,
|
|
71
|
+
});
|
|
72
|
+
const keys = await new Promise((resolve, reject) => {
|
|
73
|
+
const allKeys = [];
|
|
74
|
+
stream.on("data", (_keys) => allKeys.push(..._keys));
|
|
75
|
+
stream.on("end", () => resolve(allKeys));
|
|
76
|
+
stream.on("error", (err) => reject(err));
|
|
77
|
+
});
|
|
78
|
+
return keys.map((key) => key.replace(`${BUFFER_LIST_PREFIX}:`, ""));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.RedisJobBufferStorageStrategy = RedisJobBufferStorageStrategy;
|
|
82
|
+
//# sourceMappingURL=redis-job-buffer-storage-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-job-buffer-storage-strategy.js","sourceRoot":"","sources":["../../src/bullmq/redis-job-buffer-storage-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CustomScriptDefinition } from "../types";
|
|
2
|
+
export declare const getJobsByType: CustomScriptDefinition<[
|
|
3
|
+
totalItems: number,
|
|
4
|
+
jobIds: string[]
|
|
5
|
+
], [
|
|
6
|
+
rangeStart: number,
|
|
7
|
+
rangeEnd: number,
|
|
8
|
+
queueName: string | undefined,
|
|
9
|
+
...states: string[]
|
|
10
|
+
]>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getJobsByType = void 0;
|
|
4
|
+
const script = `--[[
|
|
5
|
+
Get job ids per provided states and filter by name
|
|
6
|
+
Input:
|
|
7
|
+
KEYS[1] 'prefix'
|
|
8
|
+
ARGV[1] start
|
|
9
|
+
ARGV[2] end
|
|
10
|
+
ARGV[3] filterName
|
|
11
|
+
ARGV[4...] types
|
|
12
|
+
]]
|
|
13
|
+
local rcall = redis.call
|
|
14
|
+
local prefix = KEYS[1]
|
|
15
|
+
local rangeStart = tonumber(ARGV[1])
|
|
16
|
+
local rangeEnd = tonumber(ARGV[2])
|
|
17
|
+
local filterName = ARGV[3]
|
|
18
|
+
local results = {}
|
|
19
|
+
|
|
20
|
+
local targetSets = {}
|
|
21
|
+
|
|
22
|
+
-- Initialize an empty array to hold the sets to unionize. The "completed" and "failed" lists
|
|
23
|
+
-- are sorted sets
|
|
24
|
+
local setsToUnionize = {}
|
|
25
|
+
local typesInUnion = {}
|
|
26
|
+
|
|
27
|
+
-- Initialize an empty array to hold lists to include. The "active" and "wait" lists are
|
|
28
|
+
-- regular lists
|
|
29
|
+
local listsToInclude = {}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
-- Iterate through ARGV starting from the first element (ARGV[1]) up to the end
|
|
33
|
+
for i = 4, #ARGV do
|
|
34
|
+
local setKey = prefix .. ARGV[i]
|
|
35
|
+
|
|
36
|
+
-- Check if the setKey is valid (e.g., it exists and is a sorted set)
|
|
37
|
+
local targetExists = redis.call('EXISTS', setKey)
|
|
38
|
+
local listType = redis.call('TYPE', setKey).ok
|
|
39
|
+
|
|
40
|
+
if targetExists == 1 and listType == 'zset' then
|
|
41
|
+
-- Add the valid set to the array
|
|
42
|
+
table.insert(setsToUnionize, setKey)
|
|
43
|
+
table.insert(typesInUnion, ARGV[i])
|
|
44
|
+
end
|
|
45
|
+
if targetExists == 1 and listType == 'list' then
|
|
46
|
+
-- Add the valid set to the array
|
|
47
|
+
table.insert(listsToInclude, setKey)
|
|
48
|
+
table.insert(typesInUnion, ARGV[i])
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
-- Define the destination key for the concatenated sorted set
|
|
53
|
+
local tempSortedSetUnionKey = prefix .. 'union:' .. table.concat(typesInUnion, ':');
|
|
54
|
+
|
|
55
|
+
if #listsToInclude == 0 and #setsToUnionize == 0 then
|
|
56
|
+
return {0, {}}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
-- Check if there are valid sets to unionize
|
|
60
|
+
if #setsToUnionize > 0 then
|
|
61
|
+
-- Use ZUNIONSTORE to concatenate the valid sorted sets into the destination key
|
|
62
|
+
local numSets = #setsToUnionize
|
|
63
|
+
redis.call('ZUNIONSTORE', tempSortedSetUnionKey, numSets, unpack(setsToUnionize))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
local originalResults = rcall("ZREVRANGE", tempSortedSetUnionKey, 0, -1)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if #listsToInclude > 0 then
|
|
70
|
+
for _, listKey in ipairs(listsToInclude) do
|
|
71
|
+
local list = rcall("LRANGE", listKey, 0, -1)
|
|
72
|
+
for _, jobId in ipairs(list) do
|
|
73
|
+
table.insert(originalResults, jobId)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
-- Define a custom comparison function for sorting in descending order
|
|
80
|
+
local function compareDescending(a, b)
|
|
81
|
+
return tonumber(a) > tonumber(b)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
-- Sort the table in descending order
|
|
85
|
+
table.sort(originalResults, compareDescending)
|
|
86
|
+
|
|
87
|
+
local filteredResults = {}
|
|
88
|
+
local totalResults = 0
|
|
89
|
+
|
|
90
|
+
for _, job in ipairs(originalResults) do
|
|
91
|
+
local jobName = rcall("HGET", prefix .. job, "name");
|
|
92
|
+
if filterName ~= "" and jobName == filterName then
|
|
93
|
+
if rangeStart <= totalResults and #filteredResults < rangeEnd then
|
|
94
|
+
table.insert(filteredResults, job)
|
|
95
|
+
end
|
|
96
|
+
totalResults = totalResults + 1
|
|
97
|
+
elseif filterName == "" then
|
|
98
|
+
if rangeStart <= totalResults and #filteredResults < rangeEnd then
|
|
99
|
+
table.insert(filteredResults, job)
|
|
100
|
+
end
|
|
101
|
+
totalResults = totalResults + 1
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
rcall("DEL", tempSortedSetUnionKey)
|
|
106
|
+
|
|
107
|
+
return {totalResults, filteredResults}
|
|
108
|
+
`;
|
|
109
|
+
exports.getJobsByType = {
|
|
110
|
+
script,
|
|
111
|
+
numberOfKeys: 1,
|
|
112
|
+
name: "getJobsByType",
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=get-jobs-by-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-jobs-by-type.js","sourceRoot":"","sources":["../../../src/bullmq/scripts/get-jobs-by-type.ts"],"names":[],"mappings":";;;AAGA,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwGd,CAAC;AAEW,QAAA,aAAa,GAQtB;IACF,MAAM;IACN,YAAY,EAAE,CAAC;IACf,IAAI,EAAE,eAAe;CACtB,CAAC"}
|