@fluojs/queue 1.0.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/service.js CHANGED
@@ -1,28 +1,24 @@
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
1
  import { cloneWithFallback } from '@fluojs/core/internal';
9
- import { getRedisClientToken, getRedisComponentId } from '@fluojs/redis';
10
- import { APPLICATION_LOGGER, BOOTSTRAP_READY_SIGNAL, COMPILED_MODULES, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
2
+ import { getRedisComponentId } from '@fluojs/redis';
3
+ import { createHash } from 'node:crypto';
11
4
  import { Queue as BullQueue, Worker as BullWorker } from 'bullmq';
12
5
  import { QueueDeadLetterManager } from './dead-letter-manager.js';
13
6
  import { normalizePositiveInteger, withTimeout } from './helpers.js';
14
7
  import { createQueuePlatformStatusSnapshot } from './status.js';
15
- import { QUEUE, QUEUE_OPTIONS } from './tokens.js';
8
+ import { getQueueLifecycleServiceToken, getQueueToken, QUEUE } from './tokens.js';
16
9
  import { discoverQueueWorkerDescriptors } from './worker-discovery.js';
17
10
  const IMMEDIATE_BOOTSTRAP_READY_SIGNAL = {
18
11
  wait: () => Promise.resolve()
19
12
  };
13
+ function createBullMqJobId(deduplicationKey) {
14
+ return `fluo-${createHash('sha256').update(deduplicationKey).digest('hex')}`;
15
+ }
20
16
  function hasQueueRedisClient(value) {
21
17
  if (typeof value !== 'object' || value === null) {
22
18
  return false;
23
19
  }
24
20
  const client = value;
25
- return typeof client.duplicate === 'function' && typeof client.rpush === 'function' && typeof client.ltrim === 'function';
21
+ return typeof client.duplicate === 'function' && typeof client.lrange === 'function' && typeof client.rpush === 'function' && typeof client.ltrim === 'function';
26
22
  }
27
23
  function isQueuePayload(value) {
28
24
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -66,11 +62,7 @@ async function closeConnection(connection) {
66
62
  * The service discovers `@QueueWorker()` providers during bootstrap, creates the
67
63
  * BullMQ queues/workers they require, and shuts them down with the application.
68
64
  */
69
- let _QueueLifecycleServic;
70
- class QueueLifecycleService {
71
- static {
72
- [_QueueLifecycleServic, _initClass] = _applyDecs(this, [Inject(QUEUE_OPTIONS, RUNTIME_CONTAINER, COMPILED_MODULES, APPLICATION_LOGGER, BOOTSTRAP_READY_SIGNAL)], []).c;
73
- }
65
+ export class QueueLifecycleService {
74
66
  descriptorsByJobType = new Map();
75
67
  queuesByJobName = new Map();
76
68
  workersByJobName = new Map();
@@ -80,17 +72,23 @@ class QueueLifecycleService {
80
72
  runningWorkerJobNames = new Set();
81
73
  failedWorkerJobNames = new Set();
82
74
  workerStartFailures = [];
75
+ compiledModulesByType;
83
76
  lifecycleState = 'idle';
84
- redisClient;
85
77
  startPromise;
86
78
  shutdownPromise;
87
79
  startupFailureRollbackPromise;
88
- constructor(options, runtimeContainer, compiledModules, logger, bootstrapReadySignal = IMMEDIATE_BOOTSTRAP_READY_SIGNAL) {
80
+ constructor(options, redisClient, runtimeContainer, compiledModules, logger, bootstrapReadySignal = IMMEDIATE_BOOTSTRAP_READY_SIGNAL, moduleContext = {
81
+ moduleType: QueueLifecycleService,
82
+ scope: 'default'
83
+ }) {
89
84
  this.options = options;
85
+ this.redisClient = redisClient;
90
86
  this.runtimeContainer = runtimeContainer;
91
87
  this.compiledModules = compiledModules;
92
88
  this.logger = logger;
93
89
  this.bootstrapReadySignal = bootstrapReadySignal;
90
+ this.moduleContext = moduleContext;
91
+ this.compiledModulesByType = new Map(this.compiledModules.map(compiledModule => [compiledModule.type, compiledModule]));
94
92
  this.deadLetterManager = new QueueDeadLetterManager(this.options, this.logger, () => this.getRedisClient());
95
93
  }
96
94
  async onApplicationBootstrap() {
@@ -107,28 +105,76 @@ class QueueLifecycleService {
107
105
  * Enqueues one job instance using the worker metadata registered for its class.
108
106
  *
109
107
  * @param job Job instance whose constructor matches a discovered `@QueueWorker()` provider.
110
- * @returns The queue-assigned job id, or an empty string when BullMQ does not provide one.
108
+ * @param options Optional producer controls, including a caller-owned deduplication key.
109
+ * @returns The backing BullMQ job id, or an empty string when BullMQ does not provide one.
111
110
  *
112
111
  * @throws {Error} When no worker is registered for the job type or the queue is not initialized.
113
112
  */
114
- async enqueue(job) {
113
+ async enqueue(job, options) {
115
114
  await this.ensureStarted();
116
115
  if (this.lifecycleState !== 'started') {
117
116
  throw new Error(`Queue lifecycle state is ${this.lifecycleState}.`);
118
117
  }
119
- const descriptor = this.descriptorsByJobType.get(job.constructor);
120
- if (!descriptor) {
121
- throw new Error(`No @QueueWorker() registered for job type ${job.constructor.name}.`);
118
+ const {
119
+ descriptor,
120
+ queue
121
+ } = this.resolveEnqueueTarget(job);
122
+ const queuedJob = await queue.add(descriptor.jobName, serializeJobPayload(job), this.createBullMqJobOptions(descriptor, options));
123
+ return queuedJob.id ?? '';
124
+ }
125
+
126
+ /**
127
+ * Atomically enqueues ordered jobs that resolve to one registered worker queue.
128
+ *
129
+ * @param entries Ordered job instances and per-job producer controls.
130
+ * @returns Backing BullMQ job ids aligned with the input order.
131
+ * @throws {Error} When any entry has no registered worker, targets another queue, or the queue is unavailable.
132
+ */
133
+ async enqueueMany(entries) {
134
+ if (entries.length === 0) {
135
+ return [];
122
136
  }
123
- const queue = this.queuesByJobName.get(descriptor.jobName);
124
- if (!queue) {
125
- throw new Error(`Queue ${descriptor.jobName} is not initialized.`);
137
+ await this.ensureStarted();
138
+ if (this.lifecycleState !== 'started') {
139
+ throw new Error(`Queue lifecycle state is ${this.lifecycleState}.`);
126
140
  }
127
- const queuedJob = await queue.add(descriptor.jobName, serializeJobPayload(job), {
128
- attempts: descriptor.attempts,
129
- backoff: toBullBackoff(descriptor.backoff)
141
+ const resolvedEntries = entries.map(entry => {
142
+ const target = this.resolveEnqueueTarget(entry.job);
143
+ return {
144
+ descriptor: target.descriptor,
145
+ options: entry.options,
146
+ payload: serializeJobPayload(entry.job),
147
+ queue: target.queue
148
+ };
130
149
  });
131
- return queuedJob.id ?? '';
150
+ const targetQueue = resolvedEntries[0]?.queue;
151
+ if (!targetQueue) {
152
+ return [];
153
+ }
154
+ if (resolvedEntries.some(entry => entry.queue !== targetQueue)) {
155
+ throw new Error('Queue batch jobs must target one registered worker queue.');
156
+ }
157
+ const queuedJobs = await targetQueue.addBulk(resolvedEntries.map(entry => ({
158
+ data: entry.payload,
159
+ name: entry.descriptor.jobName,
160
+ opts: this.createBullMqJobOptions(entry.descriptor, entry.options)
161
+ })));
162
+ return queuedJobs.map(queuedJob => queuedJob.id ?? '');
163
+ }
164
+
165
+ /**
166
+ * Reads a bounded snapshot of dead-letter records for one queue job name.
167
+ *
168
+ * Inspection reads Redis without starting workers or lifecycle-gating the read. The backing Redis client must
169
+ * remain reachable; `RedisModule` owns that shared client's shutdown.
170
+ *
171
+ * @param jobName Queue worker job name whose dead letters should be inspected.
172
+ * @param options Optional bounded inspection settings.
173
+ * @returns Valid records in newest-first order plus the malformed count for the inspected window.
174
+ * @throws The backing Redis read error when that client is unavailable or already shut down.
175
+ */
176
+ async inspectDeadLetters(jobName, options) {
177
+ return this.deadLetterManager.inspect(jobName, options);
132
178
  }
133
179
 
134
180
  /**
@@ -152,6 +198,29 @@ class QueueLifecycleService {
152
198
  workersReady: this.runningWorkerJobNames.size
153
199
  });
154
200
  }
201
+ resolveEnqueueTarget(job) {
202
+ const descriptor = this.descriptorsByJobType.get(job.constructor);
203
+ if (!descriptor) {
204
+ throw new Error(`No @QueueWorker() registered for job type ${job.constructor.name}.`);
205
+ }
206
+ const queue = this.queuesByJobName.get(descriptor.jobName);
207
+ if (!queue) {
208
+ throw new Error(`Queue ${descriptor.jobName} is not initialized.`);
209
+ }
210
+ return {
211
+ descriptor,
212
+ queue
213
+ };
214
+ }
215
+ createBullMqJobOptions(descriptor, options) {
216
+ return {
217
+ attempts: descriptor.attempts,
218
+ backoff: toBullBackoff(descriptor.backoff),
219
+ ...(options?.deduplicationKey === undefined ? {} : {
220
+ jobId: createBullMqJobId(options.deduplicationKey)
221
+ })
222
+ };
223
+ }
155
224
  async ensureStarted() {
156
225
  if (this.lifecycleState === 'started') {
157
226
  return;
@@ -172,8 +241,7 @@ class QueueLifecycleService {
172
241
  this.startPromise = undefined;
173
242
  }
174
243
  async startLifecycle() {
175
- const redis = await this.resolveRedisClient();
176
- this.redisClient = redis;
244
+ const redis = this.resolveRedisClient();
177
245
  this.descriptorsByJobType.clear();
178
246
  for (const [jobType, descriptor] of discoverQueueWorkerDescriptors(this.compiledModules, this.options, this.logger, compiledModule => this.shouldDiscoverWorkersInModule(compiledModule))) {
179
247
  this.descriptorsByJobType.set(jobType, descriptor);
@@ -188,31 +256,45 @@ class QueueLifecycleService {
188
256
  if (this.options.global) {
189
257
  return true;
190
258
  }
191
- return compiledModule.accessibleTokens.has(_QueueLifecycleServic) || compiledModule.accessibleTokens.has(QUEUE);
259
+ return this.canReachQueueRegistration(compiledModule);
260
+ }
261
+ canReachQueueRegistration(compiledModule, visited = new Set()) {
262
+ if (visited.has(compiledModule.type)) {
263
+ return false;
264
+ }
265
+ visited.add(compiledModule.type);
266
+ for (const importedModuleType of compiledModule.definition.imports ?? []) {
267
+ if (importedModuleType === this.moduleContext.moduleType) {
268
+ return true;
269
+ }
270
+ const importedModule = this.compiledModulesByType.get(importedModuleType);
271
+ if (!importedModule || !this.exportsQueueRegistration(importedModule)) {
272
+ continue;
273
+ }
274
+ if (this.canReachQueueRegistration(importedModule, visited)) {
275
+ return true;
276
+ }
277
+ }
278
+ return false;
279
+ }
280
+ exportsQueueRegistration(compiledModule) {
281
+ return compiledModule.exportedTokens.has(QueueLifecycleService) || compiledModule.exportedTokens.has(QUEUE) || compiledModule.exportedTokens.has(getQueueLifecycleServiceToken(this.options.scope)) || compiledModule.exportedTokens.has(getQueueToken(this.options.scope));
192
282
  }
193
283
  async handleStartupFailure() {
194
284
  await this.closeInitializedResources();
285
+ await this.deadLetterManager.drainPendingWrites();
195
286
  if (this.lifecycleState === 'starting') {
196
287
  this.lifecycleState = 'idle';
197
288
  }
198
- this.redisClient = undefined;
199
289
  this.startPromise = undefined;
200
290
  }
201
- async resolveRedisClient() {
202
- const redisToken = getRedisClientToken(this.options.clientName);
203
- if (!this.runtimeContainer.has(redisToken)) {
204
- throw new Error('@fluojs/queue requires a registered Redis client with duplicate(), rpush(), and ltrim() methods.');
205
- }
206
- const redisClient = await this.runtimeContainer.resolve(redisToken);
207
- if (!hasQueueRedisClient(redisClient)) {
208
- throw new Error('@fluojs/queue requires a Redis client with duplicate(), rpush(), and ltrim() methods.');
291
+ resolveRedisClient() {
292
+ if (!hasQueueRedisClient(this.redisClient)) {
293
+ throw new Error('@fluojs/queue requires a Redis client with duplicate(), lrange(), rpush(), and ltrim() methods.');
209
294
  }
210
- return redisClient;
295
+ return this.redisClient;
211
296
  }
212
297
  getRedisClient() {
213
- if (!this.redisClient) {
214
- throw new Error('@fluojs/queue Redis client is not initialized.');
215
- }
216
298
  return this.redisClient;
217
299
  }
218
300
  async initializeWorkers(redis) {
@@ -369,9 +451,10 @@ class QueueLifecycleService {
369
451
  }
370
452
  rollbackAfterWorkerStartupFailure() {
371
453
  if (!this.startupFailureRollbackPromise) {
372
- this.startupFailureRollbackPromise = this.closeInitializedResources().then(() => {
373
- this.redisClient = undefined;
374
- }).catch(rollbackError => {
454
+ this.startupFailureRollbackPromise = (async () => {
455
+ await this.closeInitializedResources();
456
+ await this.deadLetterManager.drainPendingWrites();
457
+ })().catch(rollbackError => {
375
458
  this.logger.error('Failed to roll back queue resources after worker startup failure.', rollbackError, 'QueueLifecycleService');
376
459
  });
377
460
  }
@@ -449,7 +532,6 @@ class QueueLifecycleService {
449
532
  await this.closeInitializedResources();
450
533
  await this.deadLetterManager.drainPendingWrites();
451
534
  this.lifecycleState = 'stopped';
452
- this.redisClient = undefined;
453
535
  this.startPromise = undefined;
454
536
  })();
455
537
  await this.shutdownPromise;
@@ -498,7 +580,7 @@ class QueueLifecycleService {
498
580
  } catch (error) {
499
581
  this.logger.error('Failed to close queue worker within shutdown timeout.', error, 'QueueLifecycleService');
500
582
  try {
501
- await worker.close(true);
583
+ await withTimeout(worker.close(true), this.options.workerShutdownTimeoutMs, () => new Error('queue worker force close timed out'));
502
584
  } catch (forceCloseError) {
503
585
  this.logger.error('Failed to force close queue worker during shutdown.', forceCloseError, 'QueueLifecycleService');
504
586
  }
@@ -506,20 +588,19 @@ class QueueLifecycleService {
506
588
  }
507
589
  async tryCloseQueue(queue) {
508
590
  try {
509
- await queue.close();
591
+ await withTimeout(queue.close(), this.options.workerShutdownTimeoutMs, () => new Error('queue shutdown timed out'));
510
592
  } catch (error) {
511
- this.logger.error('Failed to close queue during shutdown.', error, 'QueueLifecycleService');
593
+ this.logger.error('Failed to close queue within shutdown timeout.', error, 'QueueLifecycleService');
512
594
  }
513
595
  }
514
596
  async tryCloseOwnedConnection(connection) {
515
597
  try {
516
- await closeConnection(connection);
598
+ await withTimeout(closeConnection(connection), this.options.workerShutdownTimeoutMs, () => new Error('queue-owned Redis connection shutdown timed out'));
517
599
  } catch (error) {
518
- this.logger.error('Failed to close queue-owned Redis connection during shutdown.', error, 'QueueLifecycleService');
600
+ if (connection.status !== 'end') {
601
+ connection.disconnect();
602
+ }
603
+ this.logger.error('Failed to close queue-owned Redis connection within shutdown timeout.', error, 'QueueLifecycleService');
519
604
  }
520
605
  }
521
- static {
522
- _initClass();
523
- }
524
- }
525
- export { _QueueLifecycleServic as QueueLifecycleService };
606
+ }
package/dist/tokens.d.ts CHANGED
@@ -1,7 +1,69 @@
1
1
  import type { Token } from '@fluojs/core';
2
- import type { Queue, NormalizedQueueModuleOptions } from './types.js';
2
+ import type { ModuleType } from '@fluojs/runtime';
3
+ import type { QueueLifecycleService } from './service.js';
4
+ import type { NormalizedQueueModuleOptions, Queue } from './types.js';
5
+ /** Internal marker that distinguishes queue registration metadata from application value providers. */
6
+ export declare const QUEUE_MODULE_CONTEXT_MARKER: unique symbol;
7
+ /** Runtime metadata that binds one queue registration to its compiled module graph. */
8
+ export interface QueueModuleContext {
9
+ readonly moduleType: ModuleType;
10
+ readonly scope: string;
11
+ }
12
+ /** Internal queue registration metadata used for graph-wide worker ownership validation. */
13
+ export interface QueueRegistrationContext extends QueueModuleContext {
14
+ readonly [QUEUE_MODULE_CONTEXT_MARKER]: true;
15
+ readonly options: NormalizedQueueModuleOptions;
16
+ readonly registrationTokens: readonly Token[];
17
+ }
18
+ /**
19
+ * Normalize an optional queue registration scope.
20
+ *
21
+ * @param scope Optional scope name supplied to {@link QueueModule.forRoot}.
22
+ * @returns A trimmed non-empty scope name, or `undefined` for the default registration.
23
+ * @throws When a provided scope contains only whitespace.
24
+ */
25
+ export declare function normalizeQueueScope(scope?: string): string | undefined;
26
+ /** Queue-owned Redis client token consumed by the default queue registration. */
27
+ export declare const QUEUE_REDIS_CLIENT: Token<unknown>;
3
28
  /** Compatibility injection token for the queue facade returned by {@link QueueModule.forRoot}. */
4
29
  export declare const QUEUE: Token<Queue>;
5
30
  /** Injection token for normalized module defaults consumed by {@link QueueLifecycleService}. */
6
31
  export declare const QUEUE_OPTIONS: Token<NormalizedQueueModuleOptions>;
32
+ /** Runtime module-context token consumed by the default queue registration. */
33
+ export declare const QUEUE_MODULE_CONTEXT: Token<QueueModuleContext>;
34
+ /**
35
+ * Return the queue facade token for a default or explicitly scoped registration.
36
+ *
37
+ * @param scope Optional queue registration scope.
38
+ * @returns The compatibility {@link QUEUE} token when omitted, or a stable token for the scoped queue facade.
39
+ */
40
+ export declare function getQueueToken(scope?: string): Token<Queue>;
41
+ /**
42
+ * Return the lifecycle service token for a default or explicitly scoped queue registration.
43
+ *
44
+ * @param scope Optional queue registration scope.
45
+ * @returns The default lifecycle-service token when omitted, or a stable token for the scoped lifecycle service.
46
+ */
47
+ export declare function getQueueLifecycleServiceToken(scope?: string): Token<QueueLifecycleService>;
48
+ /**
49
+ * Return the normalized options token for a default or explicitly scoped queue registration.
50
+ *
51
+ * @param scope Optional queue registration scope.
52
+ * @returns The default options token when omitted, or a stable token for scoped normalized options.
53
+ */
54
+ export declare function getQueueOptionsToken(scope?: string): Token<NormalizedQueueModuleOptions>;
55
+ /**
56
+ * Return the queue-owned Redis client token for a default or explicitly scoped registration.
57
+ *
58
+ * @param scope Optional queue registration scope.
59
+ * @returns The default Redis client token when omitted, or a stable token for the scoped Redis dependency.
60
+ */
61
+ export declare function getQueueRedisClientToken(scope?: string): Token<unknown>;
62
+ /**
63
+ * Return the module-context token for a default or explicitly scoped queue registration.
64
+ *
65
+ * @param scope Optional queue registration scope.
66
+ * @returns The default module-context token when omitted, or a stable token for scoped queue context.
67
+ */
68
+ export declare function getQueueModuleContextToken(scope?: string): Token<QueueModuleContext>;
7
69
  //# sourceMappingURL=tokens.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAEtE,kGAAkG;AAClG,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAA4B,CAAC;AAC5D,gGAAgG;AAChG,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,4BAA4B,CAAoC,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,4BAA4B,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEtE,uGAAuG;AACvG,eAAO,MAAM,2BAA2B,eAA6C,CAAC;AAEtF,uFAAuF;AACvF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,4FAA4F;AAC5F,MAAM,WAAW,wBAAyB,SAAQ,kBAAkB;IAClE,QAAQ,CAAC,CAAC,2BAA2B,CAAC,EAAE,IAAI,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,KAAK,EAAE,CAAC;CAC/C;AAQD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYtE;AAcD,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,OAAO,CAAyC,CAAC;AACxF,kGAAkG;AAClG,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAA4B,CAAC;AAC5D,gGAAgG;AAChG,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,4BAA4B,CAAoC,CAAC;AACnG,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,kBAAkB,CAA2C,CAAC;AAEvG;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAQ1D;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,CAQ1F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,4BAA4B,CAAC,CAQxF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAQvE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAQpF"}
package/dist/tokens.js CHANGED
@@ -1,4 +1,119 @@
1
+ /** Internal marker that distinguishes queue registration metadata from application value providers. */
2
+ export const QUEUE_MODULE_CONTEXT_MARKER = Symbol('fluo.queue.module-context.marker');
3
+
4
+ /** Runtime metadata that binds one queue registration to its compiled module graph. */
5
+
6
+ /** Internal queue registration metadata used for graph-wide worker ownership validation. */
7
+
8
+ const scopedQueueTokens = new Map();
9
+ const scopedQueueLifecycleServiceTokens = new Map();
10
+ const scopedQueueOptionsTokens = new Map();
11
+ const scopedQueueRedisClientTokens = new Map();
12
+ const scopedQueueModuleContextTokens = new Map();
13
+
14
+ /**
15
+ * Normalize an optional queue registration scope.
16
+ *
17
+ * @param scope Optional scope name supplied to {@link QueueModule.forRoot}.
18
+ * @returns A trimmed non-empty scope name, or `undefined` for the default registration.
19
+ * @throws When a provided scope contains only whitespace.
20
+ */
21
+ export function normalizeQueueScope(scope) {
22
+ if (scope === undefined) {
23
+ return undefined;
24
+ }
25
+ const normalized = scope.trim();
26
+ if (normalized.length === 0) {
27
+ throw new Error('Queue scope must be a non-empty string when provided.');
28
+ }
29
+ return normalized;
30
+ }
31
+ function getScopedToken(tokens, scope, description) {
32
+ const existing = tokens.get(scope);
33
+ if (existing) {
34
+ return existing;
35
+ }
36
+ const created = Symbol(`${description}:${scope}`);
37
+ tokens.set(scope, created);
38
+ return created;
39
+ }
40
+
41
+ /** Queue-owned Redis client token consumed by the default queue registration. */
42
+ export const QUEUE_REDIS_CLIENT = Symbol.for('fluo.queue.redis-client');
1
43
  /** Compatibility injection token for the queue facade returned by {@link QueueModule.forRoot}. */
2
44
  export const QUEUE = Symbol.for('fluo.queue');
3
45
  /** Injection token for normalized module defaults consumed by {@link QueueLifecycleService}. */
4
- export const QUEUE_OPTIONS = Symbol.for('fluo.queue.options');
46
+ export const QUEUE_OPTIONS = Symbol.for('fluo.queue.options');
47
+ /** Runtime module-context token consumed by the default queue registration. */
48
+ export const QUEUE_MODULE_CONTEXT = Symbol.for('fluo.queue.module-context');
49
+
50
+ /**
51
+ * Return the queue facade token for a default or explicitly scoped registration.
52
+ *
53
+ * @param scope Optional queue registration scope.
54
+ * @returns The compatibility {@link QUEUE} token when omitted, or a stable token for the scoped queue facade.
55
+ */
56
+ export function getQueueToken(scope) {
57
+ const normalizedScope = normalizeQueueScope(scope);
58
+ if (normalizedScope === undefined) {
59
+ return QUEUE;
60
+ }
61
+ return getScopedToken(scopedQueueTokens, normalizedScope, 'fluo.queue');
62
+ }
63
+
64
+ /**
65
+ * Return the lifecycle service token for a default or explicitly scoped queue registration.
66
+ *
67
+ * @param scope Optional queue registration scope.
68
+ * @returns The default lifecycle-service token when omitted, or a stable token for the scoped lifecycle service.
69
+ */
70
+ export function getQueueLifecycleServiceToken(scope) {
71
+ const normalizedScope = normalizeQueueScope(scope);
72
+ if (normalizedScope === undefined) {
73
+ return QueueLifecycleServiceToken;
74
+ }
75
+ return getScopedToken(scopedQueueLifecycleServiceTokens, normalizedScope, 'fluo.queue.lifecycle-service');
76
+ }
77
+
78
+ /**
79
+ * Return the normalized options token for a default or explicitly scoped queue registration.
80
+ *
81
+ * @param scope Optional queue registration scope.
82
+ * @returns The default options token when omitted, or a stable token for scoped normalized options.
83
+ */
84
+ export function getQueueOptionsToken(scope) {
85
+ const normalizedScope = normalizeQueueScope(scope);
86
+ if (normalizedScope === undefined) {
87
+ return QUEUE_OPTIONS;
88
+ }
89
+ return getScopedToken(scopedQueueOptionsTokens, normalizedScope, 'fluo.queue.options');
90
+ }
91
+
92
+ /**
93
+ * Return the queue-owned Redis client token for a default or explicitly scoped registration.
94
+ *
95
+ * @param scope Optional queue registration scope.
96
+ * @returns The default Redis client token when omitted, or a stable token for the scoped Redis dependency.
97
+ */
98
+ export function getQueueRedisClientToken(scope) {
99
+ const normalizedScope = normalizeQueueScope(scope);
100
+ if (normalizedScope === undefined) {
101
+ return QUEUE_REDIS_CLIENT;
102
+ }
103
+ return getScopedToken(scopedQueueRedisClientTokens, normalizedScope, 'fluo.queue.redis-client');
104
+ }
105
+
106
+ /**
107
+ * Return the module-context token for a default or explicitly scoped queue registration.
108
+ *
109
+ * @param scope Optional queue registration scope.
110
+ * @returns The default module-context token when omitted, or a stable token for scoped queue context.
111
+ */
112
+ export function getQueueModuleContextToken(scope) {
113
+ const normalizedScope = normalizeQueueScope(scope);
114
+ if (normalizedScope === undefined) {
115
+ return QUEUE_MODULE_CONTEXT;
116
+ }
117
+ return getScopedToken(scopedQueueModuleContextTokens, normalizedScope, 'fluo.queue.module-context');
118
+ }
119
+ const QueueLifecycleServiceToken = Symbol.for('fluo.queue.lifecycle-service.default');
package/dist/types.d.ts CHANGED
@@ -5,6 +5,8 @@ export interface QueueJobType<TJob extends object = object> {
5
5
  }
6
6
  /** Supported retry backoff strategies forwarded to BullMQ workers. */
7
7
  export type QueueBackoffType = 'fixed' | 'exponential';
8
+ /** Cross-scope ownership collision action selected during queue bootstrap. */
9
+ export type QueueOwnershipEnforcement = 'warn' | 'reject';
8
10
  /** Retry timing settings applied to one queued job type. */
9
11
  export interface QueueBackoffOptions {
10
12
  delayMs?: number;
@@ -31,6 +33,16 @@ export interface QueueWorkerOptions {
31
33
  /** Module-wide defaults used when individual workers omit execution settings. */
32
34
  export interface QueueModuleOptions {
33
35
  clientName?: string;
36
+ /** Unique registration scope for non-global queue modules that need isolated providers. */
37
+ scope?: string;
38
+ /**
39
+ * Stable application-supplied identity for the Redis database and BullMQ prefix shared by this registration.
40
+ *
41
+ * Registrations that target one BullMQ backend must use the same namespace, regardless of `clientName`.
42
+ */
43
+ ownershipNamespace?: string;
44
+ /** Cross-scope collision action. Defaults to `warn` for 2.x compatibility. */
45
+ ownershipEnforcement?: QueueOwnershipEnforcement;
34
46
  /** Whether queue providers should be visible globally. Defaults to `true`. */
35
47
  global?: boolean;
36
48
  defaultAttempts?: number;
@@ -44,6 +56,9 @@ export interface QueueModuleOptions {
44
56
  /** Normalized queue options resolved once during module registration. */
45
57
  export interface NormalizedQueueModuleOptions {
46
58
  clientName?: string;
59
+ scope?: string;
60
+ ownershipNamespace?: string;
61
+ ownershipEnforcement: QueueOwnershipEnforcement;
47
62
  defaultAttempts: number;
48
63
  defaultBackoff?: QueueBackoffOptions;
49
64
  defaultConcurrency: number;
@@ -69,14 +84,70 @@ export interface QueueWorkerDescriptor {
69
84
  token: Token;
70
85
  workerName: string;
71
86
  }
87
+ /** Options for one read-only dead-letter inspection. */
88
+ export interface QueueDeadLetterInspectionOptions {
89
+ /** Maximum number of stored entries to inspect. Defaults to `100` and is capped at `1_000`. */
90
+ readonly limit?: number;
91
+ }
92
+ /** Parsed operator-facing view of one dead-letter record. */
93
+ export interface QueueDeadLetterRecord {
94
+ readonly attemptsMade: number;
95
+ readonly errorMessage: string;
96
+ readonly failedAt: string;
97
+ readonly jobId: string;
98
+ readonly jobName: string;
99
+ readonly payload: unknown;
100
+ }
101
+ /** Result of a bounded dead-letter inspection. */
102
+ export interface QueueDeadLetterInspectionResult {
103
+ /** Number of malformed stored values omitted from the inspected window. */
104
+ readonly malformedRecordCount: number;
105
+ /** Valid records in newest-first order. */
106
+ readonly records: readonly QueueDeadLetterRecord[];
107
+ }
108
+ /** Optional producer controls applied to one enqueue operation. */
109
+ export interface QueueEnqueueOptions {
110
+ /**
111
+ * Caller-supplied identity used to deduplicate repeated enqueue attempts.
112
+ *
113
+ * Queue deterministically maps this value to a BullMQ-safe backing job id,
114
+ * so callers can use arbitrary identities without inheriting
115
+ * BullMQ's colon or numeric-only custom-id restrictions.
116
+ */
117
+ readonly deduplicationKey?: string;
118
+ }
119
+ /** One ordered job and its producer controls for an atomic queue batch. */
120
+ export interface QueueEnqueueManyEntry<TJob extends object = object> {
121
+ /** Job instance whose constructor identifies the target worker. */
122
+ readonly job: TJob;
123
+ /** Optional producer controls applied only to this batch entry. */
124
+ readonly options?: QueueEnqueueOptions;
125
+ }
72
126
  /** Queue facade exposed to application code and compatibility tokens. */
73
127
  export interface Queue {
74
128
  /**
75
129
  * Enqueues one job instance for the worker registered against its class.
76
130
  *
77
131
  * @param job Job instance whose constructor identifies the target worker.
78
- * @returns The BullMQ job id generated for the enqueued payload.
132
+ * @param options Optional producer controls, including a caller-owned deduplication key.
133
+ * @returns The backing BullMQ job id for the enqueued payload.
134
+ */
135
+ enqueue<TJob extends object>(job: TJob, options?: QueueEnqueueOptions): Promise<string>;
136
+ /**
137
+ * Atomically enqueues ordered jobs that resolve to one registered worker queue.
138
+ *
139
+ * @param entries Ordered job instances and per-job producer controls.
140
+ * @returns Backing BullMQ job ids aligned with the input order.
141
+ * @throws {Error} When any entry has no registered worker, targets another queue, or the queue is unavailable.
142
+ */
143
+ enqueueMany<TJob extends object>(entries: readonly QueueEnqueueManyEntry<TJob>[]): Promise<readonly string[]>;
144
+ /**
145
+ * Reads a bounded snapshot of dead-letter records for one queue job name.
146
+ *
147
+ * @param jobName Queue worker job name whose dead letters should be inspected.
148
+ * @param options Optional bounded inspection settings.
149
+ * @returns Valid records in newest-first order plus the malformed count for the inspected window.
79
150
  */
80
- enqueue<TJob extends object>(job: TJob): Promise<string>;
151
+ inspectDeadLetters(jobName: string, options?: QueueDeadLetterInspectionOptions): Promise<QueueDeadLetterInspectionResult>;
81
152
  }
82
153
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,oFAAoF;AACpF,MAAM,WAAW,YAAY,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACxD,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;CAC9B;AAED,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,aAAa,CAAC;AAEvD,4DAA4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC;AAED,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2BAA2B,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7C,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;IAC7C,kHAAkH;IAClH,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,yEAAyE;AACzE,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2BAA2B,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5C,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;IAC7C,MAAM,EAAE,OAAO,CAAC;IAChB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,yEAAyE;AACzE,MAAM,WAAW,KAAK;IACpB;;;;;OAKG;IACH,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -6,8 +6,9 @@ import type { NormalizedQueueModuleOptions, QueueJobType, QueueWorkerDescriptor
6
6
  *
7
7
  * @param compiledModules The compiled modules.
8
8
  * @param options The options.
9
- * @param logger The logger.
9
+ * @param logger Optional logger for skipped worker registrations.
10
+ * @param moduleFilter Optional compiled-module ownership filter.
10
11
  * @returns The discover queue worker descriptors result.
11
12
  */
12
- export declare function discoverQueueWorkerDescriptors(compiledModules: readonly CompiledModule[], options: NormalizedQueueModuleOptions, logger: ApplicationLogger, moduleFilter?: DiscoveryModuleFilter): Map<QueueJobType, QueueWorkerDescriptor>;
13
+ export declare function discoverQueueWorkerDescriptors(compiledModules: readonly CompiledModule[], options: NormalizedQueueModuleOptions, logger: ApplicationLogger | undefined, moduleFilter?: DiscoveryModuleFilter): Map<QueueJobType, QueueWorkerDescriptor>;
13
14
  //# sourceMappingURL=worker-discovery.d.ts.map