@fluojs/queue 1.0.0-beta.1
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.ko.md +134 -0
- package/README.md +136 -0
- package/dist/dead-letter-manager.d.ts +28 -0
- package/dist/dead-letter-manager.d.ts.map +1 -0
- package/dist/dead-letter-manager.js +66 -0
- package/dist/decorators.d.ts +28 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +51 -0
- package/dist/helpers.d.ts +22 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +93 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/metadata.d.ts +5 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +30 -0
- package/dist/module.d.ts +30 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +65 -0
- package/dist/service.d.ts +67 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +363 -0
- package/dist/status.d.ts +27 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +101 -0
- package/dist/tokens.d.ts +7 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +4 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/worker-discovery.d.ts +4 -0
- package/dist/worker-discovery.d.ts.map +1 -0
- package/dist/worker-discovery.js +42 -0
- package/package.json +56 -0
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ModuleType } from '@fluojs/runtime';
|
|
2
|
+
import type { QueueModuleOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Runtime module entrypoint for queue lifecycle wiring.
|
|
5
|
+
*/
|
|
6
|
+
export declare class QueueModule {
|
|
7
|
+
/**
|
|
8
|
+
* Registers queue providers globally using canonical `forRoot(...)` semantics.
|
|
9
|
+
*
|
|
10
|
+
* @param options Queue runtime defaults used by discovered workers and enqueued jobs.
|
|
11
|
+
* @returns A module definition that exports `QueueLifecycleService` and the compatibility token `QUEUE`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { Module } from '@fluojs/core';
|
|
16
|
+
* import { QueueModule } from '@fluojs/queue';
|
|
17
|
+
* import { RedisModule } from '@fluojs/redis';
|
|
18
|
+
*
|
|
19
|
+
* @Module({
|
|
20
|
+
* imports: [
|
|
21
|
+
* RedisModule.forRoot({ host: 'localhost', port: 6379 }),
|
|
22
|
+
* QueueModule.forRoot({ defaultAttempts: 3 }),
|
|
23
|
+
* ],
|
|
24
|
+
* })
|
|
25
|
+
* export class AppModule {}
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
static forRoot(options?: QueueModuleOptions): ModuleType;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKhE,OAAO,KAAK,EAAgC,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAqCnF;;GAEG;AACH,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,kBAAuB,GAAG,UAAU;CAS7D"}
|
package/dist/module.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { defineModule } from '@fluojs/runtime';
|
|
2
|
+
import { normalizePositiveInteger, normalizePositiveIntegerOrFalse, normalizeRateLimiter } from './helpers.js';
|
|
3
|
+
import { QueueLifecycleService } from './service.js';
|
|
4
|
+
import { QUEUE, QUEUE_OPTIONS } from './tokens.js';
|
|
5
|
+
function normalizeQueueModuleOptions(options = {}) {
|
|
6
|
+
const defaultRateLimiter = normalizeRateLimiter(options.defaultRateLimiter);
|
|
7
|
+
return {
|
|
8
|
+
clientName: options.clientName,
|
|
9
|
+
defaultAttempts: normalizePositiveInteger(options.defaultAttempts, 1),
|
|
10
|
+
defaultBackoff: options.defaultBackoff ? {
|
|
11
|
+
delayMs: options.defaultBackoff.delayMs,
|
|
12
|
+
type: options.defaultBackoff.type
|
|
13
|
+
} : undefined,
|
|
14
|
+
defaultConcurrency: normalizePositiveInteger(options.defaultConcurrency, 1),
|
|
15
|
+
defaultDeadLetterMaxEntries: normalizePositiveIntegerOrFalse(options.defaultDeadLetterMaxEntries, 1_000),
|
|
16
|
+
defaultRateLimiter
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function createQueueProviders(options = {}) {
|
|
20
|
+
return [{
|
|
21
|
+
provide: QUEUE_OPTIONS,
|
|
22
|
+
useValue: normalizeQueueModuleOptions(options)
|
|
23
|
+
}, QueueLifecycleService, {
|
|
24
|
+
inject: [QueueLifecycleService],
|
|
25
|
+
provide: QUEUE,
|
|
26
|
+
useFactory: service => ({
|
|
27
|
+
enqueue: job => service.enqueue(job)
|
|
28
|
+
})
|
|
29
|
+
}];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Runtime module entrypoint for queue lifecycle wiring.
|
|
34
|
+
*/
|
|
35
|
+
export class QueueModule {
|
|
36
|
+
/**
|
|
37
|
+
* Registers queue providers globally using canonical `forRoot(...)` semantics.
|
|
38
|
+
*
|
|
39
|
+
* @param options Queue runtime defaults used by discovered workers and enqueued jobs.
|
|
40
|
+
* @returns A module definition that exports `QueueLifecycleService` and the compatibility token `QUEUE`.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { Module } from '@fluojs/core';
|
|
45
|
+
* import { QueueModule } from '@fluojs/queue';
|
|
46
|
+
* import { RedisModule } from '@fluojs/redis';
|
|
47
|
+
*
|
|
48
|
+
* @Module({
|
|
49
|
+
* imports: [
|
|
50
|
+
* RedisModule.forRoot({ host: 'localhost', port: 6379 }),
|
|
51
|
+
* QueueModule.forRoot({ defaultAttempts: 3 }),
|
|
52
|
+
* ],
|
|
53
|
+
* })
|
|
54
|
+
* export class AppModule {}
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
static forRoot(options = {}) {
|
|
58
|
+
class QueueModuleDefinition {}
|
|
59
|
+
return defineModule(QueueModuleDefinition, {
|
|
60
|
+
exports: [QueueLifecycleService, QUEUE],
|
|
61
|
+
global: true,
|
|
62
|
+
providers: createQueueProviders(options)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Container } from '@fluojs/di';
|
|
2
|
+
import { type ApplicationLogger, type CompiledModule, type OnApplicationBootstrap, type OnApplicationShutdown, type OnModuleDestroy } from '@fluojs/runtime';
|
|
3
|
+
import type { NormalizedQueueModuleOptions, Queue } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Lifecycle-managed queue runtime for worker discovery and job dispatch.
|
|
6
|
+
*
|
|
7
|
+
* The service discovers `@QueueWorker()` providers during bootstrap, creates the
|
|
8
|
+
* BullMQ queues/workers they require, and shuts them down with the application.
|
|
9
|
+
*/
|
|
10
|
+
export declare class QueueLifecycleService implements Queue, OnApplicationBootstrap, OnApplicationShutdown, OnModuleDestroy {
|
|
11
|
+
private readonly options;
|
|
12
|
+
private readonly runtimeContainer;
|
|
13
|
+
private readonly compiledModules;
|
|
14
|
+
private readonly logger;
|
|
15
|
+
private readonly descriptorsByJobType;
|
|
16
|
+
private readonly queuesByJobName;
|
|
17
|
+
private readonly workersByJobName;
|
|
18
|
+
private readonly ownedConnections;
|
|
19
|
+
private readonly deadLetterManager;
|
|
20
|
+
private lifecycleState;
|
|
21
|
+
private redisClient;
|
|
22
|
+
private startPromise;
|
|
23
|
+
private shutdownPromise;
|
|
24
|
+
constructor(options: NormalizedQueueModuleOptions, runtimeContainer: Container, compiledModules: readonly CompiledModule[], logger: ApplicationLogger);
|
|
25
|
+
onApplicationBootstrap(): Promise<void>;
|
|
26
|
+
onApplicationShutdown(): Promise<void>;
|
|
27
|
+
onModuleDestroy(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Enqueues one job instance using the worker metadata registered for its class.
|
|
30
|
+
*
|
|
31
|
+
* @param job Job instance whose constructor matches a discovered `@QueueWorker()` provider.
|
|
32
|
+
* @returns The queue-assigned job id, or an empty string when BullMQ does not provide one.
|
|
33
|
+
*
|
|
34
|
+
* @throws {Error} When no worker is registered for the job type or the queue is not initialized.
|
|
35
|
+
*/
|
|
36
|
+
enqueue<TJob extends object>(job: TJob): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Creates a platform status snapshot for health checks and diagnostics.
|
|
39
|
+
*
|
|
40
|
+
* @returns A structured snapshot describing lifecycle state, discovered workers, and pending dead-letter writes.
|
|
41
|
+
*/
|
|
42
|
+
createPlatformStatusSnapshot(): import("./status.js").QueuePlatformStatusSnapshot;
|
|
43
|
+
private ensureStarted;
|
|
44
|
+
private startLifecycle;
|
|
45
|
+
private handleStartupFailure;
|
|
46
|
+
private resolveRedisClient;
|
|
47
|
+
private getRedisClient;
|
|
48
|
+
private initializeWorkers;
|
|
49
|
+
private initializeWorkerResources;
|
|
50
|
+
private createQueueInstance;
|
|
51
|
+
private createWorkerInstance;
|
|
52
|
+
private createWorkerOptions;
|
|
53
|
+
private createWorkerLimiterOptions;
|
|
54
|
+
private attachWorkerFailureHandler;
|
|
55
|
+
private registerInitializedWorker;
|
|
56
|
+
private cleanupWorkerInitializationFailure;
|
|
57
|
+
private createOwnedConnection;
|
|
58
|
+
private executeWorker;
|
|
59
|
+
private resolveWorkerHandler;
|
|
60
|
+
private rehydrateWorkerPayload;
|
|
61
|
+
private shutdown;
|
|
62
|
+
private closeInitializedResources;
|
|
63
|
+
private tryCloseWorker;
|
|
64
|
+
private tryCloseQueue;
|
|
65
|
+
private tryCloseOwnedConnection;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AASzB,OAAO,KAAK,EACV,4BAA4B,EAC5B,KAAK,EAIN,MAAM,YAAY,CAAC;AA6FpB;;;;;GAKG;AACH,qBACa,qBAAsB,YAAW,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,eAAe;IAY/G,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAdzB,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAkD;IACvF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoC;IACpE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqC;IACtE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA8B;IAC/D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAyB;IAC3D,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,eAAe,CAA4B;gBAGhC,OAAO,EAAE,4BAA4B,EACrC,gBAAgB,EAAE,SAAS,EAC3B,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,MAAM,EAAE,iBAAiB;IAKtC,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAuB9D;;;;OAIG;IACH,4BAA4B;YAWd,aAAa;YAwBb,cAAc;YAad,oBAAoB;YAOpB,kBAAkB;IAgBhC,OAAO,CAAC,cAAc;YAQR,iBAAiB;YAOjB,yBAAyB;IAyBvC,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,mBAAmB;IAkB3B,OAAO,CAAC,0BAA0B;IAkBlC,OAAO,CAAC,0BAA0B;IASlC,OAAO,CAAC,yBAAyB;YASnB,kCAAkC;YAkBlC,qBAAqB;YAerB,aAAa;YAOb,oBAAoB;IAyBlC,OAAO,CAAC,sBAAsB;YAQhB,QAAQ;YAsBR,yBAAyB;YAqBzB,cAAc;YAQd,aAAa;YAQb,uBAAuB;CAOtC"}
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
let _initClass;
|
|
2
|
+
function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
|
|
3
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5
|
+
function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
|
|
6
|
+
function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
|
|
7
|
+
import { Inject } from '@fluojs/core';
|
|
8
|
+
import { cloneWithFallback } from '@fluojs/core/internal';
|
|
9
|
+
import { getRedisClientToken, getRedisComponentId } from '@fluojs/redis';
|
|
10
|
+
import { APPLICATION_LOGGER, COMPILED_MODULES, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
|
|
11
|
+
import { Queue as BullQueue, Worker as BullWorker } from 'bullmq';
|
|
12
|
+
import { QueueDeadLetterManager } from './dead-letter-manager.js';
|
|
13
|
+
import { normalizePositiveInteger } from './helpers.js';
|
|
14
|
+
import { createQueuePlatformStatusSnapshot } from './status.js';
|
|
15
|
+
import { QUEUE_OPTIONS } from './tokens.js';
|
|
16
|
+
import { discoverQueueWorkerDescriptors } from './worker-discovery.js';
|
|
17
|
+
function hasQueueRedisClient(value) {
|
|
18
|
+
if (typeof value !== 'object' || value === null) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const client = value;
|
|
22
|
+
return typeof client.duplicate === 'function' && typeof client.rpush === 'function' && typeof client.ltrim === 'function';
|
|
23
|
+
}
|
|
24
|
+
function isQueuePayload(value) {
|
|
25
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
function serializeJobPayload(job) {
|
|
28
|
+
const serialized = JSON.parse(JSON.stringify(job));
|
|
29
|
+
if (!isQueuePayload(serialized)) {
|
|
30
|
+
throw new Error('Queue payload must be a plain object after JSON serialization.');
|
|
31
|
+
}
|
|
32
|
+
return serialized;
|
|
33
|
+
}
|
|
34
|
+
function rehydrateJobPayload(jobType, payload) {
|
|
35
|
+
return Object.assign(Object.create(jobType.prototype), cloneWithFallback(payload));
|
|
36
|
+
}
|
|
37
|
+
function toBullBackoff(backoff) {
|
|
38
|
+
if (!backoff) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
delay: normalizePositiveInteger(backoff.delayMs, 1_000),
|
|
43
|
+
type: backoff.type ?? 'fixed'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async function closeConnection(connection) {
|
|
47
|
+
if (connection.status === 'end') {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await connection.quit();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
connection.disconnect();
|
|
54
|
+
if (connection.status !== 'end') {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Lifecycle-managed queue runtime for worker discovery and job dispatch.
|
|
62
|
+
*
|
|
63
|
+
* The service discovers `@QueueWorker()` providers during bootstrap, creates the
|
|
64
|
+
* BullMQ queues/workers they require, and shuts them down with the application.
|
|
65
|
+
*/
|
|
66
|
+
let _QueueLifecycleServic;
|
|
67
|
+
class QueueLifecycleService {
|
|
68
|
+
static {
|
|
69
|
+
[_QueueLifecycleServic, _initClass] = _applyDecs(this, [Inject(QUEUE_OPTIONS, RUNTIME_CONTAINER, COMPILED_MODULES, APPLICATION_LOGGER)], []).c;
|
|
70
|
+
}
|
|
71
|
+
descriptorsByJobType = new Map();
|
|
72
|
+
queuesByJobName = new Map();
|
|
73
|
+
workersByJobName = new Map();
|
|
74
|
+
ownedConnections = [];
|
|
75
|
+
deadLetterManager;
|
|
76
|
+
lifecycleState = 'idle';
|
|
77
|
+
redisClient;
|
|
78
|
+
startPromise;
|
|
79
|
+
shutdownPromise;
|
|
80
|
+
constructor(options, runtimeContainer, compiledModules, logger) {
|
|
81
|
+
this.options = options;
|
|
82
|
+
this.runtimeContainer = runtimeContainer;
|
|
83
|
+
this.compiledModules = compiledModules;
|
|
84
|
+
this.logger = logger;
|
|
85
|
+
this.deadLetterManager = new QueueDeadLetterManager(this.options, this.logger, () => this.getRedisClient());
|
|
86
|
+
}
|
|
87
|
+
async onApplicationBootstrap() {
|
|
88
|
+
await this.ensureStarted();
|
|
89
|
+
}
|
|
90
|
+
async onApplicationShutdown() {
|
|
91
|
+
await this.shutdown();
|
|
92
|
+
}
|
|
93
|
+
async onModuleDestroy() {
|
|
94
|
+
await this.shutdown();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Enqueues one job instance using the worker metadata registered for its class.
|
|
99
|
+
*
|
|
100
|
+
* @param job Job instance whose constructor matches a discovered `@QueueWorker()` provider.
|
|
101
|
+
* @returns The queue-assigned job id, or an empty string when BullMQ does not provide one.
|
|
102
|
+
*
|
|
103
|
+
* @throws {Error} When no worker is registered for the job type or the queue is not initialized.
|
|
104
|
+
*/
|
|
105
|
+
async enqueue(job) {
|
|
106
|
+
await this.ensureStarted();
|
|
107
|
+
const descriptor = this.descriptorsByJobType.get(job.constructor);
|
|
108
|
+
if (!descriptor) {
|
|
109
|
+
throw new Error(`No @QueueWorker() registered for job type ${job.constructor.name}.`);
|
|
110
|
+
}
|
|
111
|
+
const queue = this.queuesByJobName.get(descriptor.jobName);
|
|
112
|
+
if (!queue) {
|
|
113
|
+
throw new Error(`Queue ${descriptor.jobName} is not initialized.`);
|
|
114
|
+
}
|
|
115
|
+
const queuedJob = await queue.add(descriptor.jobName, serializeJobPayload(job), {
|
|
116
|
+
attempts: descriptor.attempts,
|
|
117
|
+
backoff: toBullBackoff(descriptor.backoff)
|
|
118
|
+
});
|
|
119
|
+
return queuedJob.id ?? '';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Creates a platform status snapshot for health checks and diagnostics.
|
|
124
|
+
*
|
|
125
|
+
* @returns A structured snapshot describing lifecycle state, discovered workers, and pending dead-letter writes.
|
|
126
|
+
*/
|
|
127
|
+
createPlatformStatusSnapshot() {
|
|
128
|
+
return createQueuePlatformStatusSnapshot({
|
|
129
|
+
dependencyId: getRedisComponentId(this.options.clientName),
|
|
130
|
+
lifecycleState: this.lifecycleState,
|
|
131
|
+
pendingDeadLetterWrites: this.deadLetterManager.pendingWriteCount,
|
|
132
|
+
queuesReady: this.queuesByJobName.size,
|
|
133
|
+
workersDiscovered: this.descriptorsByJobType.size,
|
|
134
|
+
workersReady: this.workersByJobName.size
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async ensureStarted() {
|
|
138
|
+
if (this.lifecycleState === 'started') {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') {
|
|
142
|
+
throw new Error(`Queue lifecycle state is ${this.lifecycleState}.`);
|
|
143
|
+
}
|
|
144
|
+
if (!this.startPromise) {
|
|
145
|
+
this.lifecycleState = 'starting';
|
|
146
|
+
this.startPromise = this.startLifecycle();
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
await this.startPromise;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
await this.handleStartupFailure();
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
this.startPromise = undefined;
|
|
155
|
+
}
|
|
156
|
+
async startLifecycle() {
|
|
157
|
+
const redis = await this.resolveRedisClient();
|
|
158
|
+
this.redisClient = redis;
|
|
159
|
+
this.descriptorsByJobType.clear();
|
|
160
|
+
for (const [jobType, descriptor] of discoverQueueWorkerDescriptors(this.compiledModules, this.options, this.logger)) {
|
|
161
|
+
this.descriptorsByJobType.set(jobType, descriptor);
|
|
162
|
+
}
|
|
163
|
+
await this.initializeWorkers(redis);
|
|
164
|
+
this.lifecycleState = 'started';
|
|
165
|
+
}
|
|
166
|
+
async handleStartupFailure() {
|
|
167
|
+
await this.closeInitializedResources();
|
|
168
|
+
this.lifecycleState = 'idle';
|
|
169
|
+
this.redisClient = undefined;
|
|
170
|
+
this.startPromise = undefined;
|
|
171
|
+
}
|
|
172
|
+
async resolveRedisClient() {
|
|
173
|
+
const redisToken = getRedisClientToken(this.options.clientName);
|
|
174
|
+
if (!this.runtimeContainer.has(redisToken)) {
|
|
175
|
+
throw new Error('@fluojs/queue requires a registered Redis client with duplicate(), rpush(), and ltrim() methods.');
|
|
176
|
+
}
|
|
177
|
+
const redisClient = await this.runtimeContainer.resolve(redisToken);
|
|
178
|
+
if (!hasQueueRedisClient(redisClient)) {
|
|
179
|
+
throw new Error('@fluojs/queue requires a Redis client with duplicate(), rpush(), and ltrim() methods.');
|
|
180
|
+
}
|
|
181
|
+
return redisClient;
|
|
182
|
+
}
|
|
183
|
+
getRedisClient() {
|
|
184
|
+
if (!this.redisClient) {
|
|
185
|
+
throw new Error('@fluojs/queue Redis client is not initialized.');
|
|
186
|
+
}
|
|
187
|
+
return this.redisClient;
|
|
188
|
+
}
|
|
189
|
+
async initializeWorkers(redis) {
|
|
190
|
+
for (const descriptor of this.descriptorsByJobType.values()) {
|
|
191
|
+
const resources = await this.initializeWorkerResources(redis, descriptor);
|
|
192
|
+
this.registerInitializedWorker(descriptor, resources);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async initializeWorkerResources(redis, descriptor) {
|
|
196
|
+
const resources = {};
|
|
197
|
+
try {
|
|
198
|
+
resources.queueConnection = await this.createOwnedConnection(redis);
|
|
199
|
+
resources.workerConnection = await this.createOwnedConnection(redis);
|
|
200
|
+
resources.queue = this.createQueueInstance(descriptor, resources.queueConnection);
|
|
201
|
+
resources.worker = this.createWorkerInstance(descriptor, resources.workerConnection);
|
|
202
|
+
this.attachWorkerFailureHandler(descriptor, resources.worker);
|
|
203
|
+
return {
|
|
204
|
+
queue: resources.queue,
|
|
205
|
+
queueConnection: resources.queueConnection,
|
|
206
|
+
worker: resources.worker,
|
|
207
|
+
workerConnection: resources.workerConnection
|
|
208
|
+
};
|
|
209
|
+
} catch (error) {
|
|
210
|
+
await this.cleanupWorkerInitializationFailure(resources);
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
createQueueInstance(descriptor, queueConnection) {
|
|
215
|
+
return new BullQueue(descriptor.jobName, {
|
|
216
|
+
connection: queueConnection
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
createWorkerInstance(descriptor, workerConnection) {
|
|
220
|
+
return new BullWorker(descriptor.jobName, async job => {
|
|
221
|
+
await this.executeWorker(descriptor, job);
|
|
222
|
+
}, this.createWorkerOptions(descriptor, workerConnection));
|
|
223
|
+
}
|
|
224
|
+
createWorkerOptions(descriptor, workerConnection) {
|
|
225
|
+
return {
|
|
226
|
+
concurrency: descriptor.concurrency,
|
|
227
|
+
connection: workerConnection,
|
|
228
|
+
...this.createWorkerLimiterOptions(descriptor)
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
createWorkerLimiterOptions(descriptor) {
|
|
232
|
+
if (!descriptor.rateLimiter) {
|
|
233
|
+
return {};
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
limiter: {
|
|
237
|
+
duration: descriptor.rateLimiter.duration,
|
|
238
|
+
max: descriptor.rateLimiter.max
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
attachWorkerFailureHandler(descriptor, worker) {
|
|
243
|
+
worker.on('failed', (job, error) => {
|
|
244
|
+
this.deadLetterManager.trackTerminalFailure(descriptor, job, error);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
registerInitializedWorker(descriptor, resources) {
|
|
248
|
+
this.queuesByJobName.set(descriptor.jobName, resources.queue);
|
|
249
|
+
this.workersByJobName.set(descriptor.jobName, resources.worker);
|
|
250
|
+
this.ownedConnections.push(resources.queueConnection, resources.workerConnection);
|
|
251
|
+
}
|
|
252
|
+
async cleanupWorkerInitializationFailure(resources) {
|
|
253
|
+
if (resources.worker) {
|
|
254
|
+
await this.tryCloseWorker(resources.worker);
|
|
255
|
+
}
|
|
256
|
+
if (resources.queue) {
|
|
257
|
+
await this.tryCloseQueue(resources.queue);
|
|
258
|
+
}
|
|
259
|
+
if (resources.workerConnection) {
|
|
260
|
+
await this.tryCloseOwnedConnection(resources.workerConnection);
|
|
261
|
+
}
|
|
262
|
+
if (resources.queueConnection) {
|
|
263
|
+
await this.tryCloseOwnedConnection(resources.queueConnection);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async createOwnedConnection(redis) {
|
|
267
|
+
const connection = redis.duplicate();
|
|
268
|
+
try {
|
|
269
|
+
if (connection.status === 'wait' || connection.status === 'reconnecting') {
|
|
270
|
+
await connection.connect();
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
await this.tryCloseOwnedConnection(connection);
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
276
|
+
return connection;
|
|
277
|
+
}
|
|
278
|
+
async executeWorker(descriptor, job) {
|
|
279
|
+
const resolvedWorker = await this.resolveWorkerHandler(descriptor);
|
|
280
|
+
const rehydratedPayload = this.rehydrateWorkerPayload(descriptor, job);
|
|
281
|
+
await Promise.resolve(resolvedWorker.handler.call(resolvedWorker.instance, rehydratedPayload));
|
|
282
|
+
}
|
|
283
|
+
async resolveWorkerHandler(descriptor) {
|
|
284
|
+
let instance;
|
|
285
|
+
try {
|
|
286
|
+
instance = await this.runtimeContainer.resolve(descriptor.token);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
throw new Error(`Failed to resolve queue worker ${descriptor.workerName} from module ${descriptor.moduleName}: ${error instanceof Error ? error.message : 'unknown error'}`);
|
|
289
|
+
}
|
|
290
|
+
const handler = instance.handle;
|
|
291
|
+
if (typeof handler !== 'function') {
|
|
292
|
+
throw new Error(`Queue worker ${descriptor.workerName} must implement handle(job).`);
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
handler: handler,
|
|
296
|
+
instance
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
rehydrateWorkerPayload(descriptor, job) {
|
|
300
|
+
if (!isQueuePayload(job.data)) {
|
|
301
|
+
throw new Error(`Queue worker ${descriptor.workerName} received a non-object payload.`);
|
|
302
|
+
}
|
|
303
|
+
return rehydrateJobPayload(descriptor.jobType, job.data);
|
|
304
|
+
}
|
|
305
|
+
async shutdown() {
|
|
306
|
+
if (this.shutdownPromise) {
|
|
307
|
+
await this.shutdownPromise;
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (this.lifecycleState === 'stopped') {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
this.lifecycleState = 'stopping';
|
|
314
|
+
this.shutdownPromise = (async () => {
|
|
315
|
+
await this.closeInitializedResources();
|
|
316
|
+
await this.deadLetterManager.drainPendingWrites();
|
|
317
|
+
this.lifecycleState = 'stopped';
|
|
318
|
+
this.startPromise = undefined;
|
|
319
|
+
})();
|
|
320
|
+
await this.shutdownPromise;
|
|
321
|
+
}
|
|
322
|
+
async closeInitializedResources() {
|
|
323
|
+
const workers = Array.from(this.workersByJobName.values());
|
|
324
|
+
const queues = Array.from(this.queuesByJobName.values());
|
|
325
|
+
const ownedConnections = this.ownedConnections.splice(0);
|
|
326
|
+
this.workersByJobName.clear();
|
|
327
|
+
this.queuesByJobName.clear();
|
|
328
|
+
for (const worker of workers) {
|
|
329
|
+
await this.tryCloseWorker(worker);
|
|
330
|
+
}
|
|
331
|
+
for (const queue of queues) {
|
|
332
|
+
await this.tryCloseQueue(queue);
|
|
333
|
+
}
|
|
334
|
+
for (const connection of ownedConnections) {
|
|
335
|
+
await this.tryCloseOwnedConnection(connection);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
async tryCloseWorker(worker) {
|
|
339
|
+
try {
|
|
340
|
+
await worker.close();
|
|
341
|
+
} catch (error) {
|
|
342
|
+
this.logger.error('Failed to close queue worker during shutdown.', error, 'QueueLifecycleService');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async tryCloseQueue(queue) {
|
|
346
|
+
try {
|
|
347
|
+
await queue.close();
|
|
348
|
+
} catch (error) {
|
|
349
|
+
this.logger.error('Failed to close queue during shutdown.', error, 'QueueLifecycleService');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async tryCloseOwnedConnection(connection) {
|
|
353
|
+
try {
|
|
354
|
+
await closeConnection(connection);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
this.logger.error('Failed to close queue-owned Redis connection during shutdown.', error, 'QueueLifecycleService');
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
static {
|
|
360
|
+
_initClass();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
export { _QueueLifecycleServic as QueueLifecycleService };
|
package/dist/status.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PlatformHealthReport, PlatformReadinessReport, PlatformSnapshot } from '@fluojs/runtime';
|
|
2
|
+
/** Lifecycle phases reported by the queue platform status adapter. */
|
|
3
|
+
export type QueueLifecycleState = 'idle' | 'starting' | 'started' | 'stopping' | 'stopped';
|
|
4
|
+
/** Input payload used to derive queue readiness, health, and dependency details. */
|
|
5
|
+
export interface QueueStatusAdapterInput {
|
|
6
|
+
dependencyId?: string;
|
|
7
|
+
lifecycleState: QueueLifecycleState;
|
|
8
|
+
pendingDeadLetterWrites: number;
|
|
9
|
+
queuesReady: number;
|
|
10
|
+
workersDiscovered: number;
|
|
11
|
+
workersReady: number;
|
|
12
|
+
}
|
|
13
|
+
/** Queue-specific platform snapshot returned to health and readiness integrations. */
|
|
14
|
+
export interface QueuePlatformStatusSnapshot {
|
|
15
|
+
readiness: PlatformReadinessReport;
|
|
16
|
+
health: PlatformHealthReport;
|
|
17
|
+
ownership: PlatformSnapshot['ownership'];
|
|
18
|
+
details: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates the queue platform snapshot consumed by status reporters.
|
|
22
|
+
*
|
|
23
|
+
* @param input Normalized queue runtime metrics and dependency information.
|
|
24
|
+
* @returns Readiness, health, ownership, and queue detail fields.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createQueuePlatformStatusSnapshot(input: QueueStatusAdapterInput): QueuePlatformStatusSnapshot;
|
|
27
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEvG,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3F,oFAAoF;AACpF,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,mBAAmB,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,sFAAsF;AACtF,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAkFD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,uBAAuB,GAAG,2BAA2B,CAkB7G"}
|
package/dist/status.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/** Lifecycle phases reported by the queue platform status adapter. */
|
|
2
|
+
|
|
3
|
+
/** Input payload used to derive queue readiness, health, and dependency details. */
|
|
4
|
+
|
|
5
|
+
/** Queue-specific platform snapshot returned to health and readiness integrations. */
|
|
6
|
+
|
|
7
|
+
function createReadiness(input) {
|
|
8
|
+
if (input.lifecycleState === 'started') {
|
|
9
|
+
return {
|
|
10
|
+
critical: true,
|
|
11
|
+
status: 'ready'
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (input.lifecycleState === 'starting') {
|
|
15
|
+
return {
|
|
16
|
+
critical: true,
|
|
17
|
+
reason: 'Queue workers are still starting.',
|
|
18
|
+
status: 'degraded'
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (input.lifecycleState === 'stopping') {
|
|
22
|
+
return {
|
|
23
|
+
critical: true,
|
|
24
|
+
reason: 'Queue workers are draining during shutdown.',
|
|
25
|
+
status: 'not-ready'
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (input.lifecycleState === 'stopped') {
|
|
29
|
+
return {
|
|
30
|
+
critical: true,
|
|
31
|
+
reason: 'Queue workers are stopped.',
|
|
32
|
+
status: 'not-ready'
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
critical: true,
|
|
37
|
+
reason: 'Queue workers are not started yet.',
|
|
38
|
+
status: 'not-ready'
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function createHealth(input) {
|
|
42
|
+
if (input.lifecycleState === 'stopped') {
|
|
43
|
+
return {
|
|
44
|
+
reason: 'Queue workers are stopped.',
|
|
45
|
+
status: 'unhealthy'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (input.lifecycleState === 'starting') {
|
|
49
|
+
return {
|
|
50
|
+
reason: 'Queue workers are still starting.',
|
|
51
|
+
status: 'degraded'
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (input.lifecycleState === 'stopping') {
|
|
55
|
+
return {
|
|
56
|
+
reason: 'Queue workers are draining during shutdown.',
|
|
57
|
+
status: 'degraded'
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (input.lifecycleState === 'started' && input.pendingDeadLetterWrites > 0) {
|
|
61
|
+
return {
|
|
62
|
+
reason: 'Queue dead-letter writes are still pending.',
|
|
63
|
+
status: 'degraded'
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (input.lifecycleState === 'idle') {
|
|
67
|
+
return {
|
|
68
|
+
reason: 'Queue workers are idle before startup.',
|
|
69
|
+
status: 'unhealthy'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
status: 'healthy'
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Creates the queue platform snapshot consumed by status reporters.
|
|
79
|
+
*
|
|
80
|
+
* @param input Normalized queue runtime metrics and dependency information.
|
|
81
|
+
* @returns Readiness, health, ownership, and queue detail fields.
|
|
82
|
+
*/
|
|
83
|
+
export function createQueuePlatformStatusSnapshot(input) {
|
|
84
|
+
return {
|
|
85
|
+
details: {
|
|
86
|
+
deadLetterDrainTimeoutMs: 5_000,
|
|
87
|
+
dependencies: [input.dependencyId ?? 'redis.default'],
|
|
88
|
+
lifecycleState: input.lifecycleState,
|
|
89
|
+
pendingDeadLetterWrites: input.pendingDeadLetterWrites,
|
|
90
|
+
queuesReady: input.queuesReady,
|
|
91
|
+
workersDiscovered: input.workersDiscovered,
|
|
92
|
+
workersReady: input.workersReady
|
|
93
|
+
},
|
|
94
|
+
health: createHealth(input),
|
|
95
|
+
ownership: {
|
|
96
|
+
externallyManaged: false,
|
|
97
|
+
ownsResources: true
|
|
98
|
+
},
|
|
99
|
+
readiness: createReadiness(input)
|
|
100
|
+
};
|
|
101
|
+
}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Token } from '@fluojs/core';
|
|
2
|
+
import type { Queue, NormalizedQueueModuleOptions } from './types.js';
|
|
3
|
+
/** Compatibility injection token for the queue facade returned by {@link QueueModule.forRoot}. */
|
|
4
|
+
export declare const QUEUE: Token<Queue>;
|
|
5
|
+
/** Injection token for normalized module defaults consumed by {@link QueueLifecycleService}. */
|
|
6
|
+
export declare const QUEUE_OPTIONS: Token<NormalizedQueueModuleOptions>;
|
|
7
|
+
//# sourceMappingURL=tokens.d.ts.map
|