@tsed/bullmq 7.47.0 → 7.48.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/README.md +30 -10
- package/jest.config.js +1 -1
- package/lib/cjs/BullMQModule.js +15 -8
- package/lib/cjs/BullMQModule.js.map +1 -1
- package/lib/esm/BullMQModule.js +15 -8
- package/lib/esm/BullMQModule.js.map +1 -1
- package/lib/tsconfig.esm.tsbuildinfo +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/config/config.d.ts +40 -1
- package/lib/types/contracts/JobMethods.d.ts +3 -2
- package/package.json +5 -5
- package/src/BullMQModule.spec.ts +242 -124
- package/src/BullMQModule.ts +25 -10
- package/src/config/config.ts +48 -3
- package/src/contracts/JobMethods.ts +4 -2
|
@@ -1,10 +1,49 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ConnectionOptions, DefaultJobOptions, QueueOptions, WorkerOptions } from "bullmq";
|
|
2
2
|
export type BullMQConfig = {
|
|
3
|
+
/**
|
|
4
|
+
* Specify queue name's to create
|
|
5
|
+
*/
|
|
3
6
|
queues: string[];
|
|
7
|
+
/**
|
|
8
|
+
* Default connection to use for queue's and worker's
|
|
9
|
+
*/
|
|
4
10
|
connection: ConnectionOptions;
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use defaultQueueOptions instead. Will be removed in the next major release
|
|
13
|
+
*/
|
|
5
14
|
defaultJobOptions?: DefaultJobOptions;
|
|
15
|
+
/**
|
|
16
|
+
* Default queue options which are applied to every queue
|
|
17
|
+
*
|
|
18
|
+
* Can be extended/overridden by `queueOptions`
|
|
19
|
+
*/
|
|
20
|
+
defaultQueueOptions?: QueueOptions;
|
|
21
|
+
/**
|
|
22
|
+
* Specify additional queue options by queue name
|
|
23
|
+
*/
|
|
24
|
+
queueOptions?: Record<string, QueueOptions>;
|
|
25
|
+
/**
|
|
26
|
+
* Disable the creation of any worker.
|
|
27
|
+
*
|
|
28
|
+
* All other worker configuration will be ignored
|
|
29
|
+
*/
|
|
6
30
|
disableWorker?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Specify for which queues to start a worker for.
|
|
33
|
+
*
|
|
34
|
+
* Defaultly for every queue added in the `queues` parameter
|
|
35
|
+
*/
|
|
7
36
|
workerQueues?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* Default worker options which are applied to every worker
|
|
39
|
+
*
|
|
40
|
+
* Can be extended/overridden by `workerOptions`
|
|
41
|
+
*/
|
|
42
|
+
defaultWorkerOptions?: WorkerOptions;
|
|
43
|
+
/**
|
|
44
|
+
* Specify additional worker options by queue name
|
|
45
|
+
*/
|
|
46
|
+
workerOptions?: Record<string, WorkerOptions>;
|
|
8
47
|
};
|
|
9
48
|
declare global {
|
|
10
49
|
namespace TsED {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { Job } from "bullmq";
|
|
2
|
+
export interface JobMethods<DataType = unknown, ReturnType = unknown> {
|
|
3
|
+
handle(payload: DataType, job: Job<DataType, ReturnType>): ReturnType | Promise<ReturnType>;
|
|
3
4
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsed/bullmq",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.48.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "BullMQ integration for Ts.ED",
|
|
6
6
|
"keywords": [
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"tslib": "2.5.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@tsed/common": "7.
|
|
33
|
-
"@tsed/core": "7.
|
|
34
|
-
"@tsed/di": "7.
|
|
32
|
+
"@tsed/common": "7.48.0",
|
|
33
|
+
"@tsed/core": "7.48.0",
|
|
34
|
+
"@tsed/di": "7.48.0",
|
|
35
35
|
"@tsed/eslint": "7.44.1",
|
|
36
|
-
"@tsed/schema": "7.
|
|
36
|
+
"@tsed/schema": "7.48.0",
|
|
37
37
|
"@tsed/typescript": "7.44.1",
|
|
38
38
|
"bullmq": "^4.12.3",
|
|
39
39
|
"eslint": "^8.12.0",
|
package/src/BullMQModule.spec.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {PlatformTest} from "@tsed/common";
|
|
2
2
|
import {catchAsyncError} from "@tsed/core";
|
|
3
3
|
import {Queue, Worker} from "bullmq";
|
|
4
|
-
import {
|
|
4
|
+
import {anything, instance, mock, verify, when} from "ts-mockito";
|
|
5
5
|
|
|
6
6
|
import "./BullMQModule";
|
|
7
7
|
import {BullMQModule} from "./BullMQModule";
|
|
@@ -10,33 +10,26 @@ import {JobMethods} from "./contracts";
|
|
|
10
10
|
import {JobController} from "./decorators";
|
|
11
11
|
import {JobDispatcher} from "./dispatchers";
|
|
12
12
|
|
|
13
|
+
const queueConstructorSpy = jest.fn();
|
|
14
|
+
const workerConstructorSpy = jest.fn();
|
|
15
|
+
|
|
13
16
|
jest.mock("bullmq", () => {
|
|
14
17
|
return {
|
|
15
18
|
Queue: class {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
constructor(name: string) {
|
|
19
|
-
this.name = name;
|
|
19
|
+
constructor(...args: any[]) {
|
|
20
|
+
queueConstructorSpy(...args);
|
|
20
21
|
}
|
|
21
22
|
close() {}
|
|
22
23
|
},
|
|
23
24
|
Worker: class {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
constructor(name: string) {
|
|
27
|
-
this.name = name;
|
|
25
|
+
constructor(...args: any[]) {
|
|
26
|
+
workerConstructorSpy(...args);
|
|
28
27
|
}
|
|
29
28
|
close() {}
|
|
30
29
|
}
|
|
31
30
|
};
|
|
32
31
|
});
|
|
33
32
|
|
|
34
|
-
const bullmq = {
|
|
35
|
-
queues: ["default", "foo", "bar"],
|
|
36
|
-
connection: {},
|
|
37
|
-
workerQueues: ["default", "foo"]
|
|
38
|
-
} as BullMQConfig;
|
|
39
|
-
|
|
40
33
|
@JobController("cron", "default", {
|
|
41
34
|
repeat: {
|
|
42
35
|
pattern: "* * * * *"
|
|
@@ -51,154 +44,279 @@ class RegularJob {
|
|
|
51
44
|
handle() {}
|
|
52
45
|
}
|
|
53
46
|
|
|
54
|
-
describe("
|
|
47
|
+
describe("BullMQModule", () => {
|
|
55
48
|
let dispatcher: JobDispatcher;
|
|
56
|
-
|
|
49
|
+
|
|
50
|
+
beforeEach(() => {
|
|
57
51
|
dispatcher = mock(JobDispatcher);
|
|
58
52
|
when(dispatcher.dispatch(CustomCronJob)).thenResolve();
|
|
59
|
-
|
|
60
|
-
await PlatformTest.create({
|
|
61
|
-
bullmq,
|
|
62
|
-
imports: [
|
|
63
|
-
{
|
|
64
|
-
token: JobDispatcher,
|
|
65
|
-
use: instance(dispatcher)
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
});
|
|
69
53
|
});
|
|
70
|
-
|
|
54
|
+
|
|
71
55
|
afterEach(PlatformTest.reset);
|
|
72
56
|
|
|
73
|
-
describe("
|
|
74
|
-
|
|
75
|
-
|
|
57
|
+
describe("configuration", () => {
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
queueConstructorSpy.mockClear();
|
|
60
|
+
workerConstructorSpy.mockClear();
|
|
76
61
|
});
|
|
77
|
-
});
|
|
78
62
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
63
|
+
describe("merges config correctly", () => {
|
|
64
|
+
beforeEach(async () => {
|
|
65
|
+
await PlatformTest.create({
|
|
66
|
+
bullmq: {
|
|
67
|
+
queues: ["default", "special"],
|
|
68
|
+
connection: {
|
|
69
|
+
connectionName: "defaultConnectionName"
|
|
70
|
+
},
|
|
71
|
+
defaultQueueOptions: {
|
|
72
|
+
defaultJobOptions: {
|
|
73
|
+
delay: 100
|
|
74
|
+
},
|
|
75
|
+
blockingConnection: true
|
|
76
|
+
},
|
|
77
|
+
queueOptions: {
|
|
78
|
+
special: {
|
|
79
|
+
connection: {
|
|
80
|
+
connectionName: "specialConnectionName"
|
|
81
|
+
},
|
|
82
|
+
defaultJobOptions: {
|
|
83
|
+
attempts: 9
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
defaultWorkerOptions: {
|
|
88
|
+
connection: {
|
|
89
|
+
connectTimeout: 123
|
|
90
|
+
},
|
|
91
|
+
concurrency: 50
|
|
92
|
+
},
|
|
93
|
+
workerOptions: {
|
|
94
|
+
special: {
|
|
95
|
+
concurrency: 1,
|
|
96
|
+
lockDuration: 2
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
imports: [
|
|
101
|
+
{
|
|
102
|
+
token: JobDispatcher,
|
|
103
|
+
use: instance(dispatcher)
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
});
|
|
107
|
+
});
|
|
82
108
|
|
|
83
|
-
|
|
84
|
-
|
|
109
|
+
it("queue", () => {
|
|
110
|
+
expect(queueConstructorSpy).toHaveBeenCalledTimes(2);
|
|
111
|
+
|
|
112
|
+
expect(queueConstructorSpy).toHaveBeenNthCalledWith(1, "default", {
|
|
113
|
+
connection: {
|
|
114
|
+
connectionName: "defaultConnectionName"
|
|
115
|
+
},
|
|
116
|
+
defaultJobOptions: {
|
|
117
|
+
delay: 100
|
|
118
|
+
},
|
|
119
|
+
blockingConnection: true
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(queueConstructorSpy).toHaveBeenNthCalledWith(2, "special", {
|
|
123
|
+
connection: {
|
|
124
|
+
connectionName: "specialConnectionName"
|
|
125
|
+
},
|
|
126
|
+
defaultJobOptions: {
|
|
127
|
+
attempts: 9,
|
|
128
|
+
delay: 100
|
|
129
|
+
},
|
|
130
|
+
blockingConnection: true
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("worker", () => {
|
|
135
|
+
expect(workerConstructorSpy).toHaveBeenCalledTimes(2);
|
|
136
|
+
|
|
137
|
+
expect(workerConstructorSpy).toHaveBeenNthCalledWith(1, "default", expect.any(Function), {
|
|
138
|
+
connection: {
|
|
139
|
+
connectTimeout: 123
|
|
140
|
+
},
|
|
141
|
+
concurrency: 50
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(workerConstructorSpy).toHaveBeenNthCalledWith(2, "special", expect.any(Function), {
|
|
145
|
+
connection: {
|
|
146
|
+
connectTimeout: 123
|
|
147
|
+
},
|
|
148
|
+
concurrency: 1,
|
|
149
|
+
lockDuration: 2
|
|
150
|
+
});
|
|
151
|
+
});
|
|
85
152
|
});
|
|
86
153
|
|
|
87
|
-
|
|
88
|
-
const
|
|
154
|
+
describe("disableWorker", () => {
|
|
155
|
+
const config = {
|
|
156
|
+
queues: ["default", "foo", "bar"],
|
|
157
|
+
connection: {},
|
|
158
|
+
disableWorker: true
|
|
159
|
+
} as BullMQConfig;
|
|
160
|
+
|
|
161
|
+
beforeEach(async () => {
|
|
162
|
+
await PlatformTest.create({
|
|
163
|
+
bullmq: config,
|
|
164
|
+
imports: [
|
|
165
|
+
{
|
|
166
|
+
token: JobDispatcher,
|
|
167
|
+
use: instance(dispatcher)
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
});
|
|
171
|
+
});
|
|
89
172
|
|
|
90
|
-
|
|
91
|
-
|
|
173
|
+
it("should not create any workers", () => {
|
|
174
|
+
expect(workerConstructorSpy).toHaveBeenCalledTimes(0);
|
|
175
|
+
});
|
|
92
176
|
});
|
|
93
177
|
|
|
94
|
-
|
|
95
|
-
|
|
178
|
+
describe("without", () => {
|
|
179
|
+
it("skips initialization", async () => {
|
|
180
|
+
await PlatformTest.create({
|
|
181
|
+
imports: [
|
|
182
|
+
{
|
|
183
|
+
token: JobDispatcher,
|
|
184
|
+
use: instance(dispatcher)
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(queueConstructorSpy).not.toHaveBeenCalled();
|
|
190
|
+
verify(dispatcher.dispatch(anything())).never();
|
|
191
|
+
});
|
|
96
192
|
});
|
|
97
193
|
});
|
|
98
194
|
|
|
99
|
-
describe("
|
|
100
|
-
|
|
101
|
-
|
|
195
|
+
describe("functionality", () => {
|
|
196
|
+
const config = {
|
|
197
|
+
queues: ["default", "foo", "bar"],
|
|
198
|
+
connection: {},
|
|
199
|
+
workerQueues: ["default", "foo"]
|
|
200
|
+
} as BullMQConfig;
|
|
201
|
+
|
|
202
|
+
beforeEach(async () => {
|
|
203
|
+
await PlatformTest.create({
|
|
204
|
+
bullmq: config,
|
|
205
|
+
imports: [
|
|
206
|
+
{
|
|
207
|
+
token: JobDispatcher,
|
|
208
|
+
use: instance(dispatcher)
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
});
|
|
212
|
+
});
|
|
102
213
|
|
|
103
|
-
|
|
104
|
-
|
|
214
|
+
describe("cronjobs", () => {
|
|
215
|
+
it("should dispatch cron jobs automatically", () => {
|
|
216
|
+
verify(dispatcher.dispatch(CustomCronJob)).once();
|
|
217
|
+
});
|
|
105
218
|
});
|
|
106
219
|
|
|
107
|
-
|
|
108
|
-
|
|
220
|
+
describe("queues", () => {
|
|
221
|
+
it("should get default", () => {
|
|
222
|
+
const instance = PlatformTest.get<Queue>("bullmq.queue.default");
|
|
109
223
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
});
|
|
224
|
+
expect(instance).toBeInstanceOf(Queue);
|
|
225
|
+
});
|
|
113
226
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
227
|
+
it.each(config.queues)("should register queue(%s)", (queue) => {
|
|
228
|
+
const instance = PlatformTest.get<Queue>(`bullmq.queue.${queue}`);
|
|
229
|
+
|
|
230
|
+
expect(instance).toBeInstanceOf(Queue);
|
|
231
|
+
});
|
|
117
232
|
|
|
118
|
-
|
|
119
|
-
|
|
233
|
+
it("should not allow direct injection of the queue", () => {
|
|
234
|
+
expect(PlatformTest.get(Queue)).not.toBeInstanceOf(Queue);
|
|
235
|
+
});
|
|
120
236
|
});
|
|
121
237
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const job = {
|
|
126
|
-
name: "regular",
|
|
127
|
-
queueName: "default",
|
|
128
|
-
data: {test: "test"}
|
|
129
|
-
};
|
|
238
|
+
describe("workers", () => {
|
|
239
|
+
it("should get default", () => {
|
|
240
|
+
const instance = PlatformTest.get<Worker>("bullmq.worker.default");
|
|
130
241
|
|
|
131
|
-
|
|
242
|
+
expect(instance).toBeInstanceOf(Worker);
|
|
243
|
+
});
|
|
132
244
|
|
|
133
|
-
|
|
245
|
+
it.each(config.workerQueues)("should register worker(%s)", (queue) => {
|
|
246
|
+
const instance = PlatformTest.get<Worker>(`bullmq.worker.${queue}`);
|
|
134
247
|
|
|
135
|
-
|
|
136
|
-
|
|
248
|
+
expect(instance).toBeInstanceOf(Worker);
|
|
249
|
+
});
|
|
137
250
|
|
|
138
|
-
|
|
139
|
-
|
|
251
|
+
it("should not register unspecified worker queue", () => {
|
|
252
|
+
expect(PlatformTest.get("bullmq.worker.bar")).toBeUndefined();
|
|
253
|
+
});
|
|
140
254
|
|
|
141
|
-
|
|
255
|
+
it("should not allow direct injection of the worker", () => {
|
|
256
|
+
expect(PlatformTest.get(Worker)).not.toBeInstanceOf(Worker);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("should run worker and execute processor", async () => {
|
|
260
|
+
const bullMQModule = PlatformTest.get<BullMQModule>(BullMQModule);
|
|
261
|
+
const worker = PlatformTest.get<JobMethods>("bullmq.job.default.regular");
|
|
262
|
+
const job = {
|
|
263
|
+
name: "regular",
|
|
264
|
+
queueName: "default",
|
|
265
|
+
data: {test: "test"}
|
|
266
|
+
};
|
|
142
267
|
|
|
143
|
-
|
|
144
|
-
name: "regular",
|
|
145
|
-
queueName: "toto",
|
|
146
|
-
data: {test: "test"}
|
|
147
|
-
};
|
|
268
|
+
jest.spyOn(worker, "handle").mockResolvedValueOnce(undefined as never);
|
|
148
269
|
|
|
149
|
-
|
|
270
|
+
await (bullMQModule as any).onProcess(job);
|
|
150
271
|
|
|
151
|
-
|
|
152
|
-
event: "BULLMQ_JOB_NOT_FOUND",
|
|
153
|
-
message: "Job regular toto not found"
|
|
272
|
+
expect(worker.handle).toHaveBeenCalledWith({test: "test"}, job);
|
|
154
273
|
});
|
|
155
|
-
});
|
|
156
274
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const worker = PlatformTest.get<JobMethods>("bullmq.job.default.regular");
|
|
160
|
-
const job = {
|
|
161
|
-
name: "regular",
|
|
162
|
-
queueName: "default",
|
|
163
|
-
data: {test: "test"}
|
|
164
|
-
};
|
|
275
|
+
it("should log warning when the worker doesn't exists", async () => {
|
|
276
|
+
const bullMQModule = PlatformTest.get<BullMQModule>(BullMQModule);
|
|
165
277
|
|
|
166
|
-
|
|
278
|
+
jest.spyOn(PlatformTest.injector.logger, "warn");
|
|
167
279
|
|
|
168
|
-
|
|
280
|
+
const job = {
|
|
281
|
+
name: "regular",
|
|
282
|
+
queueName: "toto",
|
|
283
|
+
data: {test: "test"}
|
|
284
|
+
};
|
|
169
285
|
|
|
170
|
-
|
|
286
|
+
await (bullMQModule as any).onProcess(job);
|
|
287
|
+
|
|
288
|
+
expect(PlatformTest.injector.logger.warn).toHaveBeenCalledWith({
|
|
289
|
+
event: "BULLMQ_JOB_NOT_FOUND",
|
|
290
|
+
message: "Job regular toto not found"
|
|
291
|
+
});
|
|
292
|
+
});
|
|
171
293
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
294
|
+
it("should run worker, execute processor and handle error", async () => {
|
|
295
|
+
const bullMQModule = PlatformTest.get<BullMQModule>(BullMQModule);
|
|
296
|
+
const worker = PlatformTest.get<JobMethods>("bullmq.job.default.regular");
|
|
297
|
+
const job = {
|
|
298
|
+
name: "regular",
|
|
299
|
+
queueName: "default",
|
|
300
|
+
data: {test: "test"}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
jest.spyOn(PlatformTest.injector.logger, "error");
|
|
304
|
+
|
|
305
|
+
jest.spyOn(worker, "handle").mockRejectedValue(new Error("error") as never);
|
|
306
|
+
|
|
307
|
+
const error = await catchAsyncError(() => (bullMQModule as any).onProcess(job));
|
|
308
|
+
|
|
309
|
+
expect(worker.handle).toHaveBeenCalledWith({test: "test"}, job);
|
|
310
|
+
expect(PlatformTest.injector.logger.error).toHaveBeenCalledWith({
|
|
311
|
+
duration: expect.any(Number),
|
|
312
|
+
event: "BULLMQ_JOB_ERROR",
|
|
313
|
+
message: "error",
|
|
314
|
+
reqId: expect.any(String),
|
|
315
|
+
stack: expect.any(String),
|
|
316
|
+
time: expect.any(Object)
|
|
317
|
+
});
|
|
318
|
+
expect(error?.message).toEqual("error");
|
|
180
319
|
});
|
|
181
|
-
expect(error?.message).toEqual("error");
|
|
182
320
|
});
|
|
183
321
|
});
|
|
184
322
|
});
|
|
185
|
-
|
|
186
|
-
it('skips initialization when no config is provided', async () => {
|
|
187
|
-
const injector = mock(InjectorService)
|
|
188
|
-
const dispatcher = mock(JobDispatcher);
|
|
189
|
-
await PlatformTest.create({
|
|
190
|
-
imports: [
|
|
191
|
-
{
|
|
192
|
-
token: InjectorService,
|
|
193
|
-
use: instance(injector),
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
token: JobDispatcher,
|
|
197
|
-
use: instance(dispatcher)
|
|
198
|
-
}
|
|
199
|
-
]
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
verify(injector.add(anyString(), anything())).never();
|
|
203
|
-
verify(dispatcher.dispatch(anything())).never()
|
|
204
|
-
});
|
package/src/BullMQModule.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {BeforeInit, DIContext, runInContext} from "@tsed/common";
|
|
2
2
|
import {Constant, InjectorService, Module} from "@tsed/di";
|
|
3
|
+
import {deepMerge} from "@tsed/core";
|
|
3
4
|
import {getComputedType} from "@tsed/schema";
|
|
4
|
-
import {Job, Queue, Worker} from "bullmq";
|
|
5
|
+
import {Job, Queue, type QueueOptions, Worker, type WorkerOptions} from "bullmq";
|
|
5
6
|
import {v4} from "uuid";
|
|
6
7
|
import {BullMQConfig} from "./config/config";
|
|
7
8
|
import {JobMethods} from "./contracts";
|
|
@@ -19,7 +20,9 @@ export class BullMQModule implements BeforeInit {
|
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
this.
|
|
23
|
+
if (!this.bullmq.disableWorker) {
|
|
24
|
+
this.buildWorkers();
|
|
25
|
+
}
|
|
23
26
|
this.buildQueues();
|
|
24
27
|
|
|
25
28
|
this.injector.getMany<JobMethods>("bullmq:cron").map((job) => this.dispatcher.dispatch(getComputedType(job)));
|
|
@@ -27,13 +30,19 @@ export class BullMQModule implements BeforeInit {
|
|
|
27
30
|
|
|
28
31
|
private buildQueues() {
|
|
29
32
|
this.bullmq.queues.forEach((queue) => {
|
|
33
|
+
const ops = deepMerge<QueueOptions, QueueOptions>(
|
|
34
|
+
{
|
|
35
|
+
connection: this.bullmq.connection,
|
|
36
|
+
defaultJobOptions: this.bullmq.defaultJobOptions,
|
|
37
|
+
...this.bullmq.defaultQueueOptions
|
|
38
|
+
},
|
|
39
|
+
this.bullmq.queueOptions?.[queue]
|
|
40
|
+
)!;
|
|
41
|
+
|
|
30
42
|
this.injector
|
|
31
43
|
.add(`bullmq.queue.${queue}`, {
|
|
32
44
|
type: "bullmq:queue",
|
|
33
|
-
useValue: new Queue(queue,
|
|
34
|
-
connection: this.bullmq.connection,
|
|
35
|
-
defaultJobOptions: this.bullmq.defaultJobOptions
|
|
36
|
-
}),
|
|
45
|
+
useValue: new Queue(queue, ops),
|
|
37
46
|
hooks: {
|
|
38
47
|
$onDestroy: (queue) => queue.close()
|
|
39
48
|
}
|
|
@@ -44,12 +53,18 @@ export class BullMQModule implements BeforeInit {
|
|
|
44
53
|
|
|
45
54
|
private buildWorkers() {
|
|
46
55
|
(this.bullmq.workerQueues ?? this.bullmq.queues).forEach((queue) => {
|
|
56
|
+
const ops = deepMerge<WorkerOptions, WorkerOptions>(
|
|
57
|
+
{
|
|
58
|
+
connection: this.bullmq.connection,
|
|
59
|
+
...this.bullmq.defaultWorkerOptions
|
|
60
|
+
},
|
|
61
|
+
this.bullmq.workerOptions?.[queue]
|
|
62
|
+
)!;
|
|
63
|
+
|
|
47
64
|
this.injector
|
|
48
65
|
.add(`bullmq.worker.${queue}`, {
|
|
49
66
|
type: "bullmq:worker",
|
|
50
|
-
useValue: new Worker(queue, this.onProcess.bind(this),
|
|
51
|
-
connection: this.bullmq.connection
|
|
52
|
-
}),
|
|
67
|
+
useValue: new Worker(queue, this.onProcess.bind(this), ops),
|
|
53
68
|
hooks: {
|
|
54
69
|
$onDestroy: (worker) => worker.close()
|
|
55
70
|
}
|
|
@@ -59,7 +74,7 @@ export class BullMQModule implements BeforeInit {
|
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
private getJob(name: string, queueName: string) {
|
|
62
|
-
return this.injector.get(`bullmq.job.${queueName}.${name}`);
|
|
77
|
+
return this.injector.get<JobMethods>(`bullmq.job.${queueName}.${name}`);
|
|
63
78
|
}
|
|
64
79
|
|
|
65
80
|
private async onProcess(job: Job) {
|
package/src/config/config.ts
CHANGED
|
@@ -1,13 +1,58 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type {ConnectionOptions, DefaultJobOptions, QueueOptions, WorkerOptions} from "bullmq";
|
|
2
2
|
|
|
3
3
|
export type BullMQConfig = {
|
|
4
|
+
/**
|
|
5
|
+
* Specify queue name's to create
|
|
6
|
+
*/
|
|
4
7
|
queues: string[];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Default connection to use for queue's and worker's
|
|
11
|
+
*/
|
|
5
12
|
connection: ConnectionOptions;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use defaultQueueOptions instead. Will be removed in the next major release
|
|
16
|
+
*/
|
|
6
17
|
defaultJobOptions?: DefaultJobOptions;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default queue options which are applied to every queue
|
|
21
|
+
*
|
|
22
|
+
* Can be extended/overridden by `queueOptions`
|
|
23
|
+
*/
|
|
24
|
+
defaultQueueOptions?: QueueOptions;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Specify additional queue options by queue name
|
|
28
|
+
*/
|
|
29
|
+
queueOptions?: Record<string, QueueOptions>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Disable the creation of any worker.
|
|
33
|
+
*
|
|
34
|
+
* All other worker configuration will be ignored
|
|
35
|
+
*/
|
|
7
36
|
disableWorker?: boolean;
|
|
8
|
-
|
|
9
|
-
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Specify for which queues to start a worker for.
|
|
40
|
+
*
|
|
41
|
+
* Defaultly for every queue added in the `queues` parameter
|
|
42
|
+
*/
|
|
10
43
|
workerQueues?: string[];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Default worker options which are applied to every worker
|
|
47
|
+
*
|
|
48
|
+
* Can be extended/overridden by `workerOptions`
|
|
49
|
+
*/
|
|
50
|
+
defaultWorkerOptions?: WorkerOptions;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Specify additional worker options by queue name
|
|
54
|
+
*/
|
|
55
|
+
workerOptions?: Record<string, WorkerOptions>;
|
|
11
56
|
};
|
|
12
57
|
|
|
13
58
|
declare global {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import {Job} from "bullmq";
|
|
2
|
+
|
|
3
|
+
export interface JobMethods<DataType = unknown, ReturnType = unknown> {
|
|
4
|
+
handle(payload: DataType, job: Job<DataType, ReturnType>): ReturnType | Promise<ReturnType>;
|
|
3
5
|
}
|