@dudousxd/nestjs-durable-transport-bullmq 0.1.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/dist/bullmq-transport.d.ts +43 -0
- package/dist/bullmq-transport.d.ts.map +1 -0
- package/dist/bullmq-transport.js +90 -0
- package/dist/bullmq-transport.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Heartbeat, type RemoteTask, type StepHandler, type StepResult, type Transport } from '@dudousxd/nestjs-durable-core';
|
|
2
|
+
import { type ConnectionOptions } from 'bullmq';
|
|
3
|
+
export interface BullMQTransportOptions {
|
|
4
|
+
/** ioredis connection options (or an IORedis instance). */
|
|
5
|
+
connection: ConnectionOptions;
|
|
6
|
+
/** The worker group this instance serves, required to register `handle()` consumers. */
|
|
7
|
+
group?: string;
|
|
8
|
+
/** Key prefix namespacing the durable queues. Defaults to `durable`. */
|
|
9
|
+
prefix?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A queue-backed `Transport` over BullMQ/Redis — the path for true cross-process and
|
|
13
|
+
* cross-language steps (e.g. a Python worker on the same queues). Steps are dispatched to a
|
|
14
|
+
* per-group tasks queue; results come back on a shared results queue.
|
|
15
|
+
*
|
|
16
|
+
* Run one instance engine-side (consumes results) and one per worker process (registers
|
|
17
|
+
* `handle()`s for its group). The wire payload is the documented `RemoteTask`/`StepResult` JSON,
|
|
18
|
+
* so non-Node workers interoperate.
|
|
19
|
+
*/
|
|
20
|
+
export declare class BullMQTransport implements Transport {
|
|
21
|
+
private readonly connection;
|
|
22
|
+
private readonly group?;
|
|
23
|
+
private readonly prefix;
|
|
24
|
+
private readonly handlers;
|
|
25
|
+
private readonly queues;
|
|
26
|
+
private taskWorker?;
|
|
27
|
+
private resultsWorker?;
|
|
28
|
+
constructor(options: BullMQTransportOptions);
|
|
29
|
+
private tasksName;
|
|
30
|
+
private resultsName;
|
|
31
|
+
/** Workers require `maxRetriesPerRequest: null`; preserve a passed-in IORedis instance as-is. */
|
|
32
|
+
private workerConnection;
|
|
33
|
+
private queue;
|
|
34
|
+
dispatch(task: RemoteTask): Promise<void>;
|
|
35
|
+
/** Register a step handler (worker side). Starts the group's task consumer on first call. */
|
|
36
|
+
handle(name: string, fn: StepHandler): void;
|
|
37
|
+
private runTask;
|
|
38
|
+
onResult(handler: (result: StepResult) => Promise<void>): void;
|
|
39
|
+
onHeartbeat(_handler: (beat: Heartbeat) => Promise<void>): void;
|
|
40
|
+
/** Close all workers and queues so the process can exit. */
|
|
41
|
+
close(): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=bullmq-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq-transport.d.ts","sourceRoot":"","sources":["../src/bullmq-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EAEf,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,KAAK,iBAAiB,EAAiB,MAAM,QAAQ,CAAC;AAE/D,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,UAAU,EAAE,iBAAiB,CAAC;IAC9B,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAC,CAAS;gBAEnB,OAAO,EAAE,sBAAsB;IAO3C,OAAO,CAAC,SAAS;IAGjB,OAAO,CAAC,WAAW;IAInB,iGAAiG;IACjG,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,KAAK;IASP,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C,6FAA6F;IAC7F,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI;YAU7B,OAAO;IAQrB,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAM9D,WAAW,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI/D,4DAA4D;IACtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BullMQTransport = void 0;
|
|
4
|
+
const nestjs_durable_core_1 = require("@dudousxd/nestjs-durable-core");
|
|
5
|
+
const bullmq_1 = require("bullmq");
|
|
6
|
+
/**
|
|
7
|
+
* A queue-backed `Transport` over BullMQ/Redis — the path for true cross-process and
|
|
8
|
+
* cross-language steps (e.g. a Python worker on the same queues). Steps are dispatched to a
|
|
9
|
+
* per-group tasks queue; results come back on a shared results queue.
|
|
10
|
+
*
|
|
11
|
+
* Run one instance engine-side (consumes results) and one per worker process (registers
|
|
12
|
+
* `handle()`s for its group). The wire payload is the documented `RemoteTask`/`StepResult` JSON,
|
|
13
|
+
* so non-Node workers interoperate.
|
|
14
|
+
*/
|
|
15
|
+
class BullMQTransport {
|
|
16
|
+
connection;
|
|
17
|
+
group;
|
|
18
|
+
prefix;
|
|
19
|
+
handlers = new Map();
|
|
20
|
+
queues = new Map();
|
|
21
|
+
taskWorker;
|
|
22
|
+
resultsWorker;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.connection = options.connection;
|
|
25
|
+
this.group = options.group;
|
|
26
|
+
this.prefix = options.prefix ?? 'durable';
|
|
27
|
+
}
|
|
28
|
+
// BullMQ queue names must not contain ':' (its Redis key separator), so use '-'.
|
|
29
|
+
tasksName(group) {
|
|
30
|
+
return `${this.prefix}-tasks-${group}`;
|
|
31
|
+
}
|
|
32
|
+
resultsName() {
|
|
33
|
+
return `${this.prefix}-results`;
|
|
34
|
+
}
|
|
35
|
+
/** Workers require `maxRetriesPerRequest: null`; preserve a passed-in IORedis instance as-is. */
|
|
36
|
+
workerConnection() {
|
|
37
|
+
if (this.connection && typeof this.connection === 'object' && !('options' in this.connection)) {
|
|
38
|
+
return { ...this.connection, maxRetriesPerRequest: null };
|
|
39
|
+
}
|
|
40
|
+
return this.connection;
|
|
41
|
+
}
|
|
42
|
+
queue(name) {
|
|
43
|
+
let queue = this.queues.get(name);
|
|
44
|
+
if (!queue) {
|
|
45
|
+
queue = new bullmq_1.Queue(name, { connection: this.connection });
|
|
46
|
+
this.queues.set(name, queue);
|
|
47
|
+
}
|
|
48
|
+
return queue;
|
|
49
|
+
}
|
|
50
|
+
async dispatch(task) {
|
|
51
|
+
await this.queue(this.tasksName(task.group)).add('task', task, {
|
|
52
|
+
removeOnComplete: true,
|
|
53
|
+
removeOnFail: true,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** Register a step handler (worker side). Starts the group's task consumer on first call. */
|
|
57
|
+
handle(name, fn) {
|
|
58
|
+
if (!this.group)
|
|
59
|
+
throw new Error('BullMQTransport needs a `group` to register handlers');
|
|
60
|
+
this.handlers.set(name, fn);
|
|
61
|
+
if (!this.taskWorker) {
|
|
62
|
+
this.taskWorker = new bullmq_1.Worker(this.tasksName(this.group), (job) => this.runTask(job.data), {
|
|
63
|
+
connection: this.workerConnection(),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async runTask(task) {
|
|
68
|
+
const result = await (0, nestjs_durable_core_1.runStepHandler)(task, this.handlers.get(task.name));
|
|
69
|
+
await this.queue(this.resultsName()).add('result', result, {
|
|
70
|
+
removeOnComplete: true,
|
|
71
|
+
removeOnFail: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
onResult(handler) {
|
|
75
|
+
this.resultsWorker = new bullmq_1.Worker(this.resultsName(), (job) => handler(job.data), {
|
|
76
|
+
connection: this.workerConnection(),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
onHeartbeat(_handler) {
|
|
80
|
+
// Heartbeats are not modelled over BullMQ yet; the queue's own stalled-job recovery applies.
|
|
81
|
+
}
|
|
82
|
+
/** Close all workers and queues so the process can exit. */
|
|
83
|
+
async close() {
|
|
84
|
+
await this.taskWorker?.close();
|
|
85
|
+
await this.resultsWorker?.close();
|
|
86
|
+
await Promise.all([...this.queues.values()].map((q) => q.close()));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.BullMQTransport = BullMQTransport;
|
|
90
|
+
//# sourceMappingURL=bullmq-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq-transport.js","sourceRoot":"","sources":["../src/bullmq-transport.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./bullmq-transport"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dudousxd/nestjs-durable-transport-bullmq",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "BullMQ (Redis) Transport for nestjs-durable — cross-process and cross-language steps",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Davide Carvalho",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/DavideCarvalho/nestjs-durable.git",
|
|
10
|
+
"directory": "packages/transport-bullmq"
|
|
11
|
+
},
|
|
12
|
+
"type": "commonjs",
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"types": "dist/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@dudousxd/nestjs-durable-core": ">=0.1.0 <1.0.0",
|
|
20
|
+
"bullmq": "^5.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"bullmq": "5.34.10",
|
|
24
|
+
"ioredis": "5.4.2",
|
|
25
|
+
"typescript": "5.9.3",
|
|
26
|
+
"zod": "3.25.76",
|
|
27
|
+
"@dudousxd/nestjs-durable-core": "^0.1.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p tsconfig.json",
|
|
31
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
32
|
+
}
|
|
33
|
+
}
|