@nest-batch/bullmq 0.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.
- package/LICENSE +21 -0
- package/README.md +333 -0
- package/dist/src/adapters/bullmq.adapter.d.ts +157 -0
- package/dist/src/adapters/bullmq.adapter.d.ts.map +1 -0
- package/dist/src/adapters/bullmq.adapter.js +252 -0
- package/dist/src/adapters/bullmq.adapter.js.map +1 -0
- package/dist/src/adapters/index.d.ts +12 -0
- package/dist/src/adapters/index.d.ts.map +1 -0
- package/dist/src/adapters/index.js +29 -0
- package/dist/src/adapters/index.js.map +1 -0
- package/dist/src/bullmq-execution-strategy.d.ts +59 -0
- package/dist/src/bullmq-execution-strategy.d.ts.map +1 -0
- package/dist/src/bullmq-execution-strategy.js +60 -0
- package/dist/src/bullmq-execution-strategy.js.map +1 -0
- package/dist/src/bullmq-runtime.service.d.ts +237 -0
- package/dist/src/bullmq-runtime.service.d.ts.map +1 -0
- package/dist/src/bullmq-runtime.service.js +441 -0
- package/dist/src/bullmq-runtime.service.js.map +1 -0
- package/dist/src/bullmq-schedule.service.d.ts +121 -0
- package/dist/src/bullmq-schedule.service.d.ts.map +1 -0
- package/dist/src/bullmq-schedule.service.js +232 -0
- package/dist/src/bullmq-schedule.service.js.map +1 -0
- package/dist/src/connection.d.ts +83 -0
- package/dist/src/connection.d.ts.map +1 -0
- package/dist/src/connection.js +72 -0
- package/dist/src/connection.js.map +1 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +46 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/module-options.d.ts +68 -0
- package/dist/src/module-options.d.ts.map +1 -0
- package/dist/src/module-options.js +13 -0
- package/dist/src/module-options.js.map +1 -0
- package/package.json +71 -0
- package/src/adapters/bullmq.adapter.ts +346 -0
- package/src/adapters/index.ts +11 -0
- package/src/bullmq-execution-strategy.ts +81 -0
- package/src/bullmq-runtime.service.ts +540 -0
- package/src/bullmq-schedule.service.ts +271 -0
- package/src/connection.ts +97 -0
- package/src/index.ts +28 -0
- package/src/module-options.ts +74 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API barrel for `@nest-batch/bullmq`.
|
|
3
|
+
*
|
|
4
|
+
* The host application should depend exclusively on this barrel:
|
|
5
|
+
* - `BullmqAdapter` is the new factory-pattern transport
|
|
6
|
+
* adapter (use with `NestBatchModule.forRoot({ adapters:
|
|
7
|
+
* { transport: BullmqAdapter.forRoot(...) } })`).
|
|
8
|
+
* - `BullMqExecutionStrategy` is the strategy class (also
|
|
9
|
+
* exported individually so callers can inject it directly for
|
|
10
|
+
* inspection / health checks).
|
|
11
|
+
* - `BULLMQ_MODULE_OPTIONS` is the DI token for the resolved
|
|
12
|
+
* module options bag.
|
|
13
|
+
* - the connection helpers are re-exported so callers can build
|
|
14
|
+
* a fully-resolved `BullMqResolvedConnection` from a partial
|
|
15
|
+
* `BullMqConnectionOptions` without importing the internal
|
|
16
|
+
* `connection.ts` file.
|
|
17
|
+
*
|
|
18
|
+
* The legacy `BullmqBatchModule` (with `forRoot` / `forRootAsync`
|
|
19
|
+
* static methods) has been replaced by `BullmqAdapter`. Internal
|
|
20
|
+
* modules (`./bullmq-execution-strategy`, `./module-options`,
|
|
21
|
+
* `./connection`, `./adapters/bullmq.module`) are implementation
|
|
22
|
+
* details and may move between releases.
|
|
23
|
+
*/
|
|
24
|
+
export * from './connection';
|
|
25
|
+
export * from './module-options';
|
|
26
|
+
export * from './bullmq-execution-strategy';
|
|
27
|
+
export * from './bullmq-schedule.service';
|
|
28
|
+
export * from './adapters';
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API barrel for `@nest-batch/bullmq`.
|
|
3
|
+
*
|
|
4
|
+
* The host application should depend exclusively on this barrel:
|
|
5
|
+
* - `BullmqAdapter` is the new factory-pattern transport
|
|
6
|
+
* adapter (use with `NestBatchModule.forRoot({ adapters:
|
|
7
|
+
* { transport: BullmqAdapter.forRoot(...) } })`).
|
|
8
|
+
* - `BullMqExecutionStrategy` is the strategy class (also
|
|
9
|
+
* exported individually so callers can inject it directly for
|
|
10
|
+
* inspection / health checks).
|
|
11
|
+
* - `BULLMQ_MODULE_OPTIONS` is the DI token for the resolved
|
|
12
|
+
* module options bag.
|
|
13
|
+
* - the connection helpers are re-exported so callers can build
|
|
14
|
+
* a fully-resolved `BullMqResolvedConnection` from a partial
|
|
15
|
+
* `BullMqConnectionOptions` without importing the internal
|
|
16
|
+
* `connection.ts` file.
|
|
17
|
+
*
|
|
18
|
+
* The legacy `BullmqBatchModule` (with `forRoot` / `forRootAsync`
|
|
19
|
+
* static methods) has been replaced by `BullmqAdapter`. Internal
|
|
20
|
+
* modules (`./bullmq-execution-strategy`, `./module-options`,
|
|
21
|
+
* `./connection`, `./adapters/bullmq.module`) are implementation
|
|
22
|
+
* details and may move between releases.
|
|
23
|
+
*/ "use strict";
|
|
24
|
+
Object.defineProperty(exports, "__esModule", {
|
|
25
|
+
value: true
|
|
26
|
+
});
|
|
27
|
+
_export_star(require("./connection"), exports);
|
|
28
|
+
_export_star(require("./module-options"), exports);
|
|
29
|
+
_export_star(require("./bullmq-execution-strategy"), exports);
|
|
30
|
+
_export_star(require("./bullmq-schedule.service"), exports);
|
|
31
|
+
_export_star(require("./adapters"), exports);
|
|
32
|
+
function _export_star(from, to) {
|
|
33
|
+
Object.keys(from).forEach(function(k) {
|
|
34
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
35
|
+
Object.defineProperty(to, k, {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function() {
|
|
38
|
+
return from[k];
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return from;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/**\n * Public API barrel for `@nest-batch/bullmq`.\n *\n * The host application should depend exclusively on this barrel:\n * - `BullmqAdapter` is the new factory-pattern transport\n * adapter (use with `NestBatchModule.forRoot({ adapters:\n * { transport: BullmqAdapter.forRoot(...) } })`).\n * - `BullMqExecutionStrategy` is the strategy class (also\n * exported individually so callers can inject it directly for\n * inspection / health checks).\n * - `BULLMQ_MODULE_OPTIONS` is the DI token for the resolved\n * module options bag.\n * - the connection helpers are re-exported so callers can build\n * a fully-resolved `BullMqResolvedConnection` from a partial\n * `BullMqConnectionOptions` without importing the internal\n * `connection.ts` file.\n *\n * The legacy `BullmqBatchModule` (with `forRoot` / `forRootAsync`\n * static methods) has been replaced by `BullmqAdapter`. Internal\n * modules (`./bullmq-execution-strategy`, `./module-options`,\n * `./connection`, `./adapters/bullmq.module`) are implementation\n * details and may move between releases.\n */\nexport * from './connection';\nexport * from './module-options';\nexport * from './bullmq-execution-strategy';\nexport * from './bullmq-schedule.service';\nexport * from './adapters';\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;CAsBC;;;;qBACa;qBACA;qBACA;qBACA;qBACA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { BullMqConnectionOptions, BullMqResolvedConnection } from './connection';
|
|
2
|
+
/**
|
|
3
|
+
* Public options bag for `BullmqBatchModule.forRoot()` and
|
|
4
|
+
* `forRootAsync()`.
|
|
5
|
+
*
|
|
6
|
+
* The fields cover the connections the package needs to wire up:
|
|
7
|
+
* - `connection` — the BullMQ `Queue` / `Worker` / `QueueEvents`
|
|
8
|
+
* share. T17 stores it under `BULLMQ_MODULE_OPTIONS`; T18 splits
|
|
9
|
+
* the role-specific tuning (worker `maxRetriesPerRequest: null`
|
|
10
|
+
* + `enableReadyCheck: false`; producer `enableOfflineQueue:
|
|
11
|
+
* false`) onto this same connection record and derives the
|
|
12
|
+
* per-role client from it.
|
|
13
|
+
* - `autoStartWorker` — whether the module should also start a
|
|
14
|
+
* BullMQ `Worker` on `onApplicationBootstrap`. Defaults to
|
|
15
|
+
* `false` so a launcher-only deployment does not accidentally
|
|
16
|
+
* consume Redis. T18 wires the actual worker construction.
|
|
17
|
+
*
|
|
18
|
+
* The interface extends `BullMqConnectionOptions` via composition
|
|
19
|
+
* (not `extends`) so the field can be `undefined` at the top level
|
|
20
|
+
* (the module applies its own defaults via `resolveBullMqConnection`)
|
|
21
|
+
* and the resolved form (with defaults filled in) is what gets
|
|
22
|
+
* handed to the strategy.
|
|
23
|
+
*/
|
|
24
|
+
export interface BullMqModuleOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Redis connection settings shared by the BullMQ `Queue`,
|
|
27
|
+
* `Worker`, and `QueueEvents` clients this package builds.
|
|
28
|
+
* Optional — defaults are filled in by
|
|
29
|
+
* `resolveBullMqConnection()`.
|
|
30
|
+
*/
|
|
31
|
+
connection?: BullMqConnectionOptions;
|
|
32
|
+
/**
|
|
33
|
+
* Whether the module should also spin up a BullMQ `Worker` on
|
|
34
|
+
* `OnApplicationBootstrap`. Default: `false` (launcher-only).
|
|
35
|
+
* Reserved for T18 — the skeleton in T17 does not implement
|
|
36
|
+
* worker lifecycle.
|
|
37
|
+
*/
|
|
38
|
+
autoStartWorker?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Reserved for future per-adapter extension. Adapter packages
|
|
41
|
+
* (e.g. a future `@nest-batch/mikro-orm` companion) can read
|
|
42
|
+
* the full options bag through this field for cross-cutting
|
|
43
|
+
* config.
|
|
44
|
+
*/
|
|
45
|
+
readonly [key: string]: unknown;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Token under which the resolved module options are registered.
|
|
49
|
+
*
|
|
50
|
+
* The strategy injects the options via this token so it can build
|
|
51
|
+
* the per-role BullMQ connection clients. The token is a
|
|
52
|
+
* package-scoped `Symbol.for` key (mirroring
|
|
53
|
+
* `@nest-batch/core/MODULE_OPTIONS_TOKEN`) so it is unique across
|
|
54
|
+
* the host process even if multiple `@nest-batch/bullmq` versions
|
|
55
|
+
* are loaded.
|
|
56
|
+
*/
|
|
57
|
+
export declare const BULLMQ_MODULE_OPTIONS: symbol;
|
|
58
|
+
/**
|
|
59
|
+
* Type alias for the fully-resolved options bag. Used by
|
|
60
|
+
* `BullmqBatchModule.forRoot()` to freeze the resolved value under
|
|
61
|
+
* `BULLMQ_MODULE_OPTIONS` and by the strategy to type its injected
|
|
62
|
+
* dependency.
|
|
63
|
+
*/
|
|
64
|
+
export interface ResolvedBullMqModuleOptions {
|
|
65
|
+
readonly connection: BullMqResolvedConnection;
|
|
66
|
+
readonly autoStartWorker: boolean;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=module-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-options.d.ts","sourceRoot":"","sources":["../../src/module-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,uBAAuB,CAAC;IAErC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;OAKG;IACH,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAEnC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "BULLMQ_MODULE_OPTIONS", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return BULLMQ_MODULE_OPTIONS;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const BULLMQ_MODULE_OPTIONS = Symbol.for('@nest-batch/bullmq/MODULE_OPTIONS');
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=module-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/module-options.ts"],"sourcesContent":["import type { BullMqConnectionOptions, BullMqResolvedConnection } from './connection';\n\n/**\n * Public options bag for `BullmqBatchModule.forRoot()` and\n * `forRootAsync()`.\n *\n * The fields cover the connections the package needs to wire up:\n * - `connection` — the BullMQ `Queue` / `Worker` / `QueueEvents`\n * share. T17 stores it under `BULLMQ_MODULE_OPTIONS`; T18 splits\n * the role-specific tuning (worker `maxRetriesPerRequest: null`\n * + `enableReadyCheck: false`; producer `enableOfflineQueue:\n * false`) onto this same connection record and derives the\n * per-role client from it.\n * - `autoStartWorker` — whether the module should also start a\n * BullMQ `Worker` on `onApplicationBootstrap`. Defaults to\n * `false` so a launcher-only deployment does not accidentally\n * consume Redis. T18 wires the actual worker construction.\n *\n * The interface extends `BullMqConnectionOptions` via composition\n * (not `extends`) so the field can be `undefined` at the top level\n * (the module applies its own defaults via `resolveBullMqConnection`)\n * and the resolved form (with defaults filled in) is what gets\n * handed to the strategy.\n */\nexport interface BullMqModuleOptions {\n /**\n * Redis connection settings shared by the BullMQ `Queue`,\n * `Worker`, and `QueueEvents` clients this package builds.\n * Optional — defaults are filled in by\n * `resolveBullMqConnection()`.\n */\n connection?: BullMqConnectionOptions;\n\n /**\n * Whether the module should also spin up a BullMQ `Worker` on\n * `OnApplicationBootstrap`. Default: `false` (launcher-only).\n * Reserved for T18 — the skeleton in T17 does not implement\n * worker lifecycle.\n */\n autoStartWorker?: boolean;\n\n /**\n * Reserved for future per-adapter extension. Adapter packages\n * (e.g. a future `@nest-batch/mikro-orm` companion) can read\n * the full options bag through this field for cross-cutting\n * config.\n */\n readonly [key: string]: unknown;\n}\n\n/**\n * Token under which the resolved module options are registered.\n *\n * The strategy injects the options via this token so it can build\n * the per-role BullMQ connection clients. The token is a\n * package-scoped `Symbol.for` key (mirroring\n * `@nest-batch/core/MODULE_OPTIONS_TOKEN`) so it is unique across\n * the host process even if multiple `@nest-batch/bullmq` versions\n * are loaded.\n */\nexport const BULLMQ_MODULE_OPTIONS: symbol = Symbol.for(\n '@nest-batch/bullmq/MODULE_OPTIONS',\n);\n\n/**\n * Type alias for the fully-resolved options bag. Used by\n * `BullmqBatchModule.forRoot()` to freeze the resolved value under\n * `BULLMQ_MODULE_OPTIONS` and by the strategy to type its injected\n * dependency.\n */\nexport interface ResolvedBullMqModuleOptions {\n readonly connection: BullMqResolvedConnection;\n readonly autoStartWorker: boolean;\n}\n"],"names":["BULLMQ_MODULE_OPTIONS","Symbol","for"],"mappings":";;;;+BA4DaA;;;eAAAA;;;AAAN,MAAMA,wBAAgCC,OAAOC,GAAG,CACrD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nest-batch/bullmq",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "BullMQ runtime adapter for @nest-batch/core — runs batch jobs and partitioned steps as BullMQ queues and workers.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "easdkr",
|
|
7
|
+
"homepage": "https://github.com/easdkr/nest-batch/tree/main/packages/bullmq#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/easdkr/nest-batch.git",
|
|
11
|
+
"directory": "packages/bullmq"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/easdkr/nest-batch/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"nestjs",
|
|
18
|
+
"batch",
|
|
19
|
+
"bullmq",
|
|
20
|
+
"queue",
|
|
21
|
+
"worker"
|
|
22
|
+
],
|
|
23
|
+
"main": "dist/src/index.js",
|
|
24
|
+
"types": "dist/src/index.d.ts",
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/src",
|
|
27
|
+
"src",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@nestjs/common": "^10 || ^11",
|
|
35
|
+
"@nestjs/core": "^10 || ^11",
|
|
36
|
+
"bullmq": "^5.0.0",
|
|
37
|
+
"@nest-batch/core": "^0.2.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependenciesMeta": {
|
|
40
|
+
"@nest-batch/core": {
|
|
41
|
+
"optional": false
|
|
42
|
+
},
|
|
43
|
+
"@nestjs/common": {
|
|
44
|
+
"optional": false
|
|
45
|
+
},
|
|
46
|
+
"@nestjs/core": {
|
|
47
|
+
"optional": false
|
|
48
|
+
},
|
|
49
|
+
"bullmq": {
|
|
50
|
+
"optional": false
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@nestjs/common": "^11.0.0",
|
|
55
|
+
"@nestjs/core": "^11.0.0",
|
|
56
|
+
"@swc/cli": "^0.7.0",
|
|
57
|
+
"@swc/core": "^1.10.7",
|
|
58
|
+
"@types/node": "^22.0.0",
|
|
59
|
+
"bullmq": "^5.0.0",
|
|
60
|
+
"reflect-metadata": "^0.2.2",
|
|
61
|
+
"typescript": "^5.5.0",
|
|
62
|
+
"vitest": "^2.0.0",
|
|
63
|
+
"@nest-batch/core": "0.2.0"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"build": "swc src -d dist --config-file ../../.swcrc && tsc --emitDeclarationOnly -p tsconfig.build.json",
|
|
67
|
+
"test": "vitest run",
|
|
68
|
+
"test:watch": "vitest",
|
|
69
|
+
"typecheck": "tsc --noEmit"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { Module, type DynamicModule, type Provider } from '@nestjs/common';
|
|
2
|
+
import { EXECUTION_STRATEGY, type BatchAdapter } from '@nest-batch/core';
|
|
3
|
+
|
|
4
|
+
import { BullMqExecutionStrategy } from '../bullmq-execution-strategy';
|
|
5
|
+
import { BullmqRuntimeService } from '../bullmq-runtime.service';
|
|
6
|
+
import { BullmqScheduleService } from '../bullmq-schedule.service';
|
|
7
|
+
import { resolveBullMqConnection } from '../connection';
|
|
8
|
+
import {
|
|
9
|
+
BULLMQ_MODULE_OPTIONS,
|
|
10
|
+
type BullMqModuleOptions,
|
|
11
|
+
type ResolvedBullMqModuleOptions,
|
|
12
|
+
} from '../module-options';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Empty Nest module class that owns the BullMQ transport's
|
|
16
|
+
* provider graph.
|
|
17
|
+
*
|
|
18
|
+
* Mirrors `InProcessModule` in `@nest-batch/core/src/adapters/
|
|
19
|
+
* in-process.adapter.ts`: the class has no body on purpose. It is
|
|
20
|
+
* purely a `DynamicModule` carrier — Nest's module system requires
|
|
21
|
+
* *some* class to identify the module, and the empty class is the
|
|
22
|
+
* minimum possible surface (no decorators, no lifecycle hooks, no
|
|
23
|
+
* metadata). All real behaviour lives on the providers.
|
|
24
|
+
*/
|
|
25
|
+
@Module({})
|
|
26
|
+
export class BullmqModule {}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sentinel token for the async-options factory chain.
|
|
30
|
+
*
|
|
31
|
+
* `forRootAsync` registers a `useFactory` provider under this token
|
|
32
|
+
* that runs the user's factory, then a second provider
|
|
33
|
+
* (`BULLMQ_MODULE_OPTIONS`) that depends on it and freezes the
|
|
34
|
+
* resolved options. A duplicate `provide` for
|
|
35
|
+
* `BULLMQ_MODULE_OPTIONS` would crash Nest's container, so the
|
|
36
|
+
* chain uses this private symbol as the intermediate step.
|
|
37
|
+
*
|
|
38
|
+
* Mirrors the `Symbol.for('@nest-batch/bullmq/OPTIONS_FACTORY')`
|
|
39
|
+
* used by the legacy `BullmqBatchModule.forRootAsync()` — the
|
|
40
|
+
* `Symbol.for` key is process-scoped and stable across module
|
|
41
|
+
* versions, so any host still wiring up the legacy class is not
|
|
42
|
+
* affected.
|
|
43
|
+
*/
|
|
44
|
+
const OPTIONS_FACTORY: symbol = Symbol.for('@nest-batch/bullmq/OPTIONS_FACTORY');
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The list of exports the BullMQ adapter's `DynamicModule` exposes
|
|
48
|
+
* to the host application.
|
|
49
|
+
*
|
|
50
|
+
* Centralised so the sync and async paths stay in lockstep — any
|
|
51
|
+
* future addition (e.g. a `BullmqScheduler` controller) only needs
|
|
52
|
+
* to be added here.
|
|
53
|
+
*
|
|
54
|
+
* The set mirrors the legacy `BullmqBatchModule.forRoot()` exports
|
|
55
|
+
* (the `forRootAsync()` legacy path was missing
|
|
56
|
+
* `BullmqRuntimeService` from `exports` — that omission is fixed
|
|
57
|
+
* here, both paths now export the same five entries).
|
|
58
|
+
*
|
|
59
|
+
* - `EXECUTION_STRATEGY` — the DI token, so host code (e.g. a
|
|
60
|
+
* `/healthz` endpoint) can resolve the strategy class via
|
|
61
|
+
* `moduleRef.get(EXECUTION_STRATEGY)`.
|
|
62
|
+
* - `BULLMQ_MODULE_OPTIONS` — the resolved connection / worker
|
|
63
|
+
* config bag, for inspection and (future) for per-role client
|
|
64
|
+
* builders.
|
|
65
|
+
* - `BullMqExecutionStrategy` — the concrete class, for type-
|
|
66
|
+
* strict consumers that prefer class injection.
|
|
67
|
+
* - `BullmqRuntimeService` — the runtime that owns the
|
|
68
|
+
* `Queue` / `Worker` / `QueueEvents` lifecycle.
|
|
69
|
+
* - `BullmqScheduleService` — the runtime that owns the
|
|
70
|
+
* `@BatchScheduled` cron-to-BullMQ translation.
|
|
71
|
+
*/
|
|
72
|
+
const ADAPTER_EXPORTS: ReadonlyArray<symbol | typeof BullMqExecutionStrategy | typeof BullmqRuntimeService | typeof BullmqScheduleService> = [
|
|
73
|
+
EXECUTION_STRATEGY,
|
|
74
|
+
BULLMQ_MODULE_OPTIONS,
|
|
75
|
+
BullMqExecutionStrategy,
|
|
76
|
+
BullmqRuntimeService,
|
|
77
|
+
BullmqScheduleService,
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* `BullmqAdapter` — the transport adapter for `@nest-batch/bullmq`
|
|
82
|
+
* used by the new factory-pattern
|
|
83
|
+
* `NestBatchModule.forRoot({ adapters: { transport, ... } })` API.
|
|
84
|
+
*
|
|
85
|
+
* Overrides the default `EXECUTION_STRATEGY` token with a BullMQ-
|
|
86
|
+
* backed `IExecutionStrategy` (`BullMqExecutionStrategy`) and wires
|
|
87
|
+
* the runtime services that own the BullMQ client lifecycle
|
|
88
|
+
* (`BullmqRuntimeService` for step enqueue + worker, plus
|
|
89
|
+
* `BullmqScheduleService` for `@BatchScheduled` cron entries).
|
|
90
|
+
*
|
|
91
|
+
* Two static methods:
|
|
92
|
+
*
|
|
93
|
+
* - `forRoot(options)` — synchronous configuration. The
|
|
94
|
+
* connection options are resolved up-front and frozen under
|
|
95
|
+
* the `BULLMQ_MODULE_OPTIONS` token. Use this when the Redis
|
|
96
|
+
* host is known at module composition time.
|
|
97
|
+
*
|
|
98
|
+
* - `forRootAsync({ imports, inject, useFactory })` — async
|
|
99
|
+
* configuration. The factory is registered as a sentinel
|
|
100
|
+
* provider; the `BULLMQ_MODULE_OPTIONS` provider depends on
|
|
101
|
+
* it. Use this when the connection comes from a config
|
|
102
|
+
* service or another async source.
|
|
103
|
+
*
|
|
104
|
+
* The two methods share the same provider list via the
|
|
105
|
+
* `buildStaticProviders` helper — the only difference is whether
|
|
106
|
+
* `BULLMQ_MODULE_OPTIONS` is a value provider (sync) or a factory
|
|
107
|
+
* provider that resolves the user's `useFactory` result (async).
|
|
108
|
+
*
|
|
109
|
+
* `globalProviders` is intentionally omitted. The recommended path
|
|
110
|
+
* is to expose host-visible providers via the module's own
|
|
111
|
+
* `exports` (see `ADAPTER_EXPORTS` above) — the `BatchAdapter`
|
|
112
|
+
* interface's `globalProviders` field is for runtime classes the
|
|
113
|
+
* adapter's own module needs but that core itself would also
|
|
114
|
+
* re-export. `JobLauncher` (registered by `NestBatchModule`, not
|
|
115
|
+
* by this adapter) injects the strategy by the `EXECUTION_STRATEGY`
|
|
116
|
+
* token, which is already in `exports`, so the resolution chain
|
|
117
|
+
* works without core having to know which adapter is active.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* // Synchronous wiring (connection known at module-build time)
|
|
122
|
+
* import { Module } from '@nestjs/common';
|
|
123
|
+
* import { NestBatchModule, InProcessAdapter } from '@nest-batch/core';
|
|
124
|
+
* import { MikroOrmAdapter } from '@nest-batch/mikro-orm';
|
|
125
|
+
* import { BullmqAdapter } from '@nest-batch/bullmq';
|
|
126
|
+
*
|
|
127
|
+
* @Module({
|
|
128
|
+
* imports: [
|
|
129
|
+
* NestBatchModule.forRoot({
|
|
130
|
+
* adapters: {
|
|
131
|
+
* persistence: MikroOrmAdapter,
|
|
132
|
+
* transport: BullmqAdapter.forRoot({
|
|
133
|
+
* connection: {
|
|
134
|
+
* host: process.env.REDIS_HOST,
|
|
135
|
+
* port: Number(process.env.REDIS_PORT),
|
|
136
|
+
* keyPrefix: 'nest-batch:',
|
|
137
|
+
* },
|
|
138
|
+
* autoStartWorker: true,
|
|
139
|
+
* }),
|
|
140
|
+
* },
|
|
141
|
+
* }),
|
|
142
|
+
* ],
|
|
143
|
+
* })
|
|
144
|
+
* class AppModule {}
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts
|
|
149
|
+
* // Async wiring (connection sourced from ConfigService)
|
|
150
|
+
* BullmqAdapter.forRootAsync({
|
|
151
|
+
* imports: [ConfigModule],
|
|
152
|
+
* inject: [ConfigService],
|
|
153
|
+
* useFactory: (cfg: ConfigService) => ({
|
|
154
|
+
* connection: {
|
|
155
|
+
* host: cfg.get<string>('redis.host'),
|
|
156
|
+
* port: cfg.get<number>('redis.port'),
|
|
157
|
+
* password: cfg.get<string>('redis.password'),
|
|
158
|
+
* },
|
|
159
|
+
* }),
|
|
160
|
+
* });
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export class BullmqAdapter {
|
|
164
|
+
/**
|
|
165
|
+
* Synchronous configuration.
|
|
166
|
+
*
|
|
167
|
+
* Resolves the connection options up-front (`resolveBullMqConnection`
|
|
168
|
+
* fills in defaults + freezes the bag) and emits a
|
|
169
|
+
* `BatchAdapter` whose `module` is a `global: true`
|
|
170
|
+
* `DynamicModule` registering the strategy class, the runtime
|
|
171
|
+
* services, the `EXECUTION_STRATEGY` binding, and the resolved
|
|
172
|
+
* options as a value provider under `BULLMQ_MODULE_OPTIONS`.
|
|
173
|
+
*
|
|
174
|
+
* No options object is required: the module accepts an empty
|
|
175
|
+
* `{}` and applies all defaults (host `127.0.0.1`, port `6379`,
|
|
176
|
+
* keyPrefix `nest-batch:`, no auth, no TLS, `autoStartWorker:
|
|
177
|
+
* false`).
|
|
178
|
+
*
|
|
179
|
+
* @param options - Connection + worker config. All fields optional.
|
|
180
|
+
* @returns A `BatchAdapter` with `name: 'bullmq'` and the
|
|
181
|
+
* `BullmqModule` dynamic module.
|
|
182
|
+
*/
|
|
183
|
+
static forRoot(options: BullMqModuleOptions = {}): BatchAdapter {
|
|
184
|
+
const resolved: ResolvedBullMqModuleOptions = Object.freeze({
|
|
185
|
+
connection: resolveBullMqConnection(options.connection),
|
|
186
|
+
autoStartWorker: options.autoStartWorker ?? false,
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
name: 'bullmq',
|
|
190
|
+
module: buildBullmqDynamicModule({
|
|
191
|
+
providers: buildStaticProviders(resolved),
|
|
192
|
+
}),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Async configuration — useful when the Redis connection comes
|
|
198
|
+
* from a config service or another async provider.
|
|
199
|
+
*
|
|
200
|
+
* The shape mirrors `NestBatchModule.forRootAsync`:
|
|
201
|
+
* - `imports` is forwarded to the resulting
|
|
202
|
+
* `DynamicModule.imports` (so `ConfigModule` is available
|
|
203
|
+
* when the factory runs).
|
|
204
|
+
* - `inject` lists the providers the factory needs in its
|
|
205
|
+
* argument list.
|
|
206
|
+
* - `useFactory` resolves the options bag at module-build
|
|
207
|
+
* time. The factory's return value is treated as
|
|
208
|
+
* `BullMqModuleOptions` and is fed through
|
|
209
|
+
* `resolveBullMqConnection` by the `BULLMQ_MODULE_OPTIONS`
|
|
210
|
+
* factory provider (defaults applied, bag frozen).
|
|
211
|
+
*
|
|
212
|
+
* Implementation note: the factory is registered under the
|
|
213
|
+
* package-private `OPTIONS_FACTORY` sentinel token; the
|
|
214
|
+
* `BULLMQ_MODULE_OPTIONS` provider depends on it. This is the
|
|
215
|
+
* same chain the legacy `BullmqBatchModule.forRootAsync` used
|
|
216
|
+
* — the dynamic module is built off the static provider list,
|
|
217
|
+
* with the static `BULLMQ_MODULE_OPTIONS` value provider
|
|
218
|
+
* replaced by the async factory pair.
|
|
219
|
+
*
|
|
220
|
+
* @param asyncOptions - `{ imports, inject, useFactory }` bag.
|
|
221
|
+
* `useFactory` is required; `imports` and `inject` are
|
|
222
|
+
* optional and default to `[]`.
|
|
223
|
+
* @returns A `BatchAdapter` with `name: 'bullmq'` and the
|
|
224
|
+
* `BullmqModule` dynamic module (with `imports` wired).
|
|
225
|
+
*/
|
|
226
|
+
static forRootAsync(asyncOptions: {
|
|
227
|
+
imports?: DynamicModule['imports'];
|
|
228
|
+
inject?: readonly unknown[];
|
|
229
|
+
useFactory: (
|
|
230
|
+
...args: unknown[]
|
|
231
|
+
) => Promise<BullMqModuleOptions> | BullMqModuleOptions;
|
|
232
|
+
}): BatchAdapter {
|
|
233
|
+
const factoryProvider: Provider = {
|
|
234
|
+
provide: OPTIONS_FACTORY,
|
|
235
|
+
useFactory: asyncOptions.useFactory as (...args: unknown[]) => unknown,
|
|
236
|
+
inject: [...(asyncOptions.inject ?? [])] as Array<string | symbol | Function>,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const mergedOptionsProvider: Provider = {
|
|
240
|
+
provide: BULLMQ_MODULE_OPTIONS,
|
|
241
|
+
useFactory: (
|
|
242
|
+
fromFactory: BullMqModuleOptions | undefined,
|
|
243
|
+
): ResolvedBullMqModuleOptions => {
|
|
244
|
+
return Object.freeze({
|
|
245
|
+
connection: resolveBullMqConnection(fromFactory?.connection),
|
|
246
|
+
autoStartWorker: fromFactory?.autoStartWorker ?? false,
|
|
247
|
+
});
|
|
248
|
+
},
|
|
249
|
+
inject: [OPTIONS_FACTORY],
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// The static provider list is the same as `forRoot` except
|
|
253
|
+
// the value provider for `BULLMQ_MODULE_OPTIONS` is replaced
|
|
254
|
+
// with the async factory above (a duplicate `provide` would
|
|
255
|
+
// crash Nest's container). We seed `buildStaticProviders`
|
|
256
|
+
// with a placeholder resolved bag (its value is discarded
|
|
257
|
+
// — the async provider overrides the slot) so the function
|
|
258
|
+
// can be the single source of truth for the rest of the
|
|
259
|
+
// provider list.
|
|
260
|
+
const baseProviders = buildStaticProviders(
|
|
261
|
+
Object.freeze({
|
|
262
|
+
connection: resolveBullMqConnection(undefined),
|
|
263
|
+
autoStartWorker: false,
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
const filtered = baseProviders.filter(
|
|
267
|
+
(p) =>
|
|
268
|
+
!(
|
|
269
|
+
typeof p === 'object' &&
|
|
270
|
+
p !== null &&
|
|
271
|
+
'provide' in p &&
|
|
272
|
+
(p as { provide: unknown }).provide === BULLMQ_MODULE_OPTIONS
|
|
273
|
+
),
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
name: 'bullmq',
|
|
278
|
+
module: buildBullmqDynamicModule({
|
|
279
|
+
providers: [factoryProvider, mergedOptionsProvider, ...filtered],
|
|
280
|
+
imports: asyncOptions.imports,
|
|
281
|
+
}),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Build the static provider list shared by `forRoot()` and
|
|
288
|
+
* `forRootAsync()`.
|
|
289
|
+
*
|
|
290
|
+
* Centralised so the sync and async paths declare the same set of
|
|
291
|
+
* providers (and any future addition — e.g. a per-role client
|
|
292
|
+
* builder — only needs to be added here).
|
|
293
|
+
*
|
|
294
|
+
* The async path then filters the `BULLMQ_MODULE_OPTIONS` entry
|
|
295
|
+
* out of the returned array and replaces it with the factory
|
|
296
|
+
* pair. Everything else is shared.
|
|
297
|
+
*/
|
|
298
|
+
function buildStaticProviders(
|
|
299
|
+
resolved: ResolvedBullMqModuleOptions,
|
|
300
|
+
): Provider[] {
|
|
301
|
+
return [
|
|
302
|
+
BullMqExecutionStrategy,
|
|
303
|
+
BullmqRuntimeService,
|
|
304
|
+
BullmqScheduleService,
|
|
305
|
+
{
|
|
306
|
+
provide: EXECUTION_STRATEGY,
|
|
307
|
+
useExisting: BullMqExecutionStrategy,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
provide: BULLMQ_MODULE_OPTIONS,
|
|
311
|
+
useValue: resolved,
|
|
312
|
+
},
|
|
313
|
+
];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Build the `DynamicModule` payload for the BullMQ adapter.
|
|
318
|
+
*
|
|
319
|
+
* Extracted from the two factory methods so the provider /
|
|
320
|
+
* export / global-true shape lives in one place. NestJS's
|
|
321
|
+
* `validateExportedProvider` check rejects an `exports` entry
|
|
322
|
+
* that is not in `providers` (or imported), so adding to one
|
|
323
|
+
* without the other is a silent runtime failure — keeping the
|
|
324
|
+
* two arrays synchronised by construction is the safest
|
|
325
|
+
* pattern.
|
|
326
|
+
*
|
|
327
|
+
* `imports` is optional: `forRoot` does not need any (it has no
|
|
328
|
+
* async providers), `forRootAsync` forwards the user's
|
|
329
|
+
* `imports` (typically `ConfigModule`) so the factory's
|
|
330
|
+
* `inject` targets resolve.
|
|
331
|
+
*/
|
|
332
|
+
function buildBullmqDynamicModule(args: {
|
|
333
|
+
providers: Provider[];
|
|
334
|
+
imports?: DynamicModule['imports'];
|
|
335
|
+
}): DynamicModule {
|
|
336
|
+
const module: DynamicModule = {
|
|
337
|
+
module: BullmqModule,
|
|
338
|
+
global: true,
|
|
339
|
+
providers: args.providers,
|
|
340
|
+
exports: [...ADAPTER_EXPORTS],
|
|
341
|
+
};
|
|
342
|
+
if (args.imports !== undefined) {
|
|
343
|
+
return { ...module, imports: [...args.imports] };
|
|
344
|
+
}
|
|
345
|
+
return module;
|
|
346
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface for the BullMQ adapter factory.
|
|
3
|
+
*
|
|
4
|
+
* The `BullmqAdapter` is the only entry point the host should
|
|
5
|
+
* depend on for the new factory-pattern API. The internal module
|
|
6
|
+
* class (`BullmqModule`) is exported alongside it as a NestJS
|
|
7
|
+
* identifier — it is safe to reference from test code that needs
|
|
8
|
+
* to assert on the `module` field of the adapter value, but it
|
|
9
|
+
* has no runtime surface beyond the empty class body.
|
|
10
|
+
*/
|
|
11
|
+
export * from './bullmq.adapter';
|