@fluojs/queue 1.0.1 → 2.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/module.js CHANGED
@@ -1,11 +1,24 @@
1
+ import { getRedisClientToken } from '@fluojs/redis';
1
2
  import { defineModule } from '@fluojs/runtime';
3
+ import { APPLICATION_LOGGER, BOOTSTRAP_READY_SIGNAL, COMPILED_MODULES, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
2
4
  import { normalizePositiveInteger, normalizePositiveIntegerOrFalse, normalizeRateLimiter } from './helpers.js';
3
5
  import { QueueLifecycleService } from './service.js';
4
- import { QUEUE, QUEUE_OPTIONS } from './tokens.js';
6
+ import { getQueueLifecycleServiceToken, getQueueModuleContextToken, getQueueOptionsToken, getQueueRedisClientToken as getQueueScopedRedisClientToken, getQueueToken, normalizeQueueScope, QUEUE } from './tokens.js';
7
+ function hasQueueRedisClient(value) {
8
+ if (typeof value !== 'object' || value === null) {
9
+ return false;
10
+ }
11
+ const client = value;
12
+ return typeof client.duplicate === 'function' && typeof client.lrange === 'function' && typeof client.rpush === 'function' && typeof client.ltrim === 'function';
13
+ }
5
14
  function normalizeQueueModuleOptions(options = {}) {
6
15
  const defaultRateLimiter = normalizeRateLimiter(options.defaultRateLimiter);
16
+ const scope = normalizeQueueScope(options.scope);
7
17
  return {
8
18
  clientName: options.clientName,
19
+ ...(scope ? {
20
+ scope
21
+ } : {}),
9
22
  defaultAttempts: normalizePositiveInteger(options.defaultAttempts, 1),
10
23
  defaultBackoff: options.defaultBackoff ? {
11
24
  delayMs: options.defaultBackoff.delayMs,
@@ -14,20 +27,79 @@ function normalizeQueueModuleOptions(options = {}) {
14
27
  defaultConcurrency: normalizePositiveInteger(options.defaultConcurrency, 1),
15
28
  defaultDeadLetterMaxEntries: normalizePositiveIntegerOrFalse(options.defaultDeadLetterMaxEntries, 1_000),
16
29
  defaultRateLimiter,
30
+ global: options.global ?? true,
17
31
  workerShutdownTimeoutMs: normalizePositiveInteger(options.workerShutdownTimeoutMs, 30_000)
18
32
  };
19
33
  }
20
- function createQueueProviders(options = {}) {
21
- return [{
22
- provide: QUEUE_OPTIONS,
23
- useValue: normalizeQueueModuleOptions(options)
24
- }, QueueLifecycleService, {
25
- inject: [QueueLifecycleService],
26
- provide: QUEUE,
34
+ function getQueueProviderTokens(scope) {
35
+ return {
36
+ lifecycleServiceToken: getQueueLifecycleServiceToken(scope),
37
+ moduleContextToken: getQueueModuleContextToken(scope),
38
+ optionsToken: getQueueOptionsToken(scope),
39
+ queueRedisClientToken: getQueueScopedRedisClientToken(scope),
40
+ queueToken: getQueueToken(scope)
41
+ };
42
+ }
43
+ function moduleCanAccessQueueRegistration(compiledModule, moduleType) {
44
+ return compiledModule.type === moduleType || (compiledModule.definition.imports ?? []).includes(moduleType);
45
+ }
46
+ function canAccessRedisClient(compiledModules, moduleContext, redisToken) {
47
+ return compiledModules.some(compiledModule => moduleCanAccessQueueRegistration(compiledModule, moduleContext.moduleType) && compiledModule.accessibleTokens.has(redisToken));
48
+ }
49
+ function formatQueueScope(scope) {
50
+ return scope ?? 'default';
51
+ }
52
+ function createQueueProviders(normalizedOptions, moduleType) {
53
+ const tokens = getQueueProviderTokens(normalizedOptions.scope);
54
+ const providers = [{
55
+ provide: tokens.optionsToken,
56
+ useValue: normalizedOptions
57
+ }, {
58
+ provide: tokens.moduleContextToken,
59
+ useValue: {
60
+ moduleType,
61
+ scope: formatQueueScope(normalizedOptions.scope)
62
+ }
63
+ }, {
64
+ inject: [tokens.optionsToken, RUNTIME_CONTAINER, COMPILED_MODULES, tokens.moduleContextToken],
65
+ provide: tokens.queueRedisClientToken,
66
+ useFactory: async (...deps) => {
67
+ const [resolvedOptions, runtimeContainer, compiledModules, moduleContext] = deps;
68
+ const redisToken = getRedisClientToken(resolvedOptions.clientName);
69
+ if (!canAccessRedisClient(compiledModules, moduleContext, redisToken)) {
70
+ throw new Error(`@fluojs/queue cannot access Redis client token ${String(redisToken)} from queue scope "${moduleContext.scope}". Import and export the matching RedisModule.forRoot(...) registration through the same module graph.`);
71
+ }
72
+ if (!runtimeContainer.has(redisToken)) {
73
+ throw new Error('@fluojs/queue requires a registered Redis client with duplicate(), lrange(), rpush(), and ltrim() methods.');
74
+ }
75
+ const redisClient = await runtimeContainer.resolve(redisToken);
76
+ if (!hasQueueRedisClient(redisClient)) {
77
+ throw new Error('@fluojs/queue requires a Redis client with duplicate(), lrange(), rpush(), and ltrim() methods.');
78
+ }
79
+ return redisClient;
80
+ }
81
+ }, {
82
+ inject: [tokens.optionsToken, tokens.queueRedisClientToken, RUNTIME_CONTAINER, COMPILED_MODULES, APPLICATION_LOGGER, BOOTSTRAP_READY_SIGNAL, tokens.moduleContextToken],
83
+ provide: tokens.lifecycleServiceToken,
84
+ useFactory: (...deps) => {
85
+ const typedDeps = deps;
86
+ return new QueueLifecycleService(...typedDeps);
87
+ }
88
+ }, {
89
+ inject: [tokens.lifecycleServiceToken],
90
+ provide: tokens.queueToken,
27
91
  useFactory: service => ({
28
- enqueue: job => service.enqueue(job)
92
+ enqueue: job => service.enqueue(job),
93
+ inspectDeadLetters: (jobName, options) => service.inspectDeadLetters(jobName, options)
29
94
  })
30
95
  }];
96
+ if (normalizedOptions.scope === undefined) {
97
+ providers.push({
98
+ provide: QueueLifecycleService,
99
+ useExisting: tokens.lifecycleServiceToken
100
+ });
101
+ }
102
+ return providers;
31
103
  }
32
104
 
33
105
  /**
@@ -35,10 +107,10 @@ function createQueueProviders(options = {}) {
35
107
  */
36
108
  export class QueueModule {
37
109
  /**
38
- * Registers queue providers globally using canonical `forRoot(...)` semantics.
110
+ * Registers queue providers using canonical `forRoot(...)` semantics.
39
111
  *
40
112
  * @param options Queue runtime defaults used by discovered workers and enqueued jobs.
41
- * @returns A module definition that exports `QueueLifecycleService` and the compatibility token `QUEUE`.
113
+ * @returns A module definition that exports default queue tokens when `scope` is omitted, or scoped queue tokens when `scope` is set.
42
114
  *
43
115
  * @example
44
116
  * ```ts
@@ -56,11 +128,13 @@ export class QueueModule {
56
128
  * ```
57
129
  */
58
130
  static forRoot(options = {}) {
131
+ const normalizedOptions = normalizeQueueModuleOptions(options);
132
+ const tokens = getQueueProviderTokens(normalizedOptions.scope);
59
133
  class QueueModuleDefinition {}
60
134
  return defineModule(QueueModuleDefinition, {
61
- exports: [QueueLifecycleService, QUEUE],
62
- global: options.global ?? true,
63
- providers: createQueueProviders(options)
135
+ exports: normalizedOptions.scope === undefined ? [QueueLifecycleService, tokens.lifecycleServiceToken, QUEUE] : [tokens.lifecycleServiceToken, tokens.queueToken],
136
+ global: normalizedOptions.global,
137
+ providers: createQueueProviders(normalizedOptions, QueueModuleDefinition)
64
138
  });
65
139
  }
66
140
  }
package/dist/service.d.ts CHANGED
@@ -1,7 +1,24 @@
1
1
  import type { Container } from '@fluojs/di';
2
2
  import type { ApplicationLogger, CompiledModule, OnApplicationBootstrap, OnApplicationShutdown, OnModuleDestroy } from '@fluojs/runtime';
3
- import { type BootstrapReadySignal } from '@fluojs/runtime/internal';
4
- import type { NormalizedQueueModuleOptions, Queue } from './types.js';
3
+ import type { BootstrapReadySignal } from '@fluojs/runtime/internal';
4
+ import { type ConnectionOptions } from 'bullmq';
5
+ import { type QueueRedisDeadLetterClient } from './dead-letter-manager.js';
6
+ import { type QueuePlatformStatusSnapshot } from './status.js';
7
+ import type { QueueModuleContext } from './tokens.js';
8
+ import type { NormalizedQueueModuleOptions, Queue, QueueDeadLetterInspectionOptions, QueueDeadLetterInspectionResult } from './types.js';
9
+ type QueueOwnedConnection = ConnectionOptions & {
10
+ connect(): Promise<unknown>;
11
+ disconnect(): void;
12
+ quit(): Promise<unknown>;
13
+ maxRetriesPerRequest?: number | null;
14
+ status?: string;
15
+ };
16
+ interface QueueBullMqConnectionOptions {
17
+ maxRetriesPerRequest: null;
18
+ }
19
+ interface QueueRedisClient extends QueueRedisDeadLetterClient {
20
+ duplicate(options?: QueueBullMqConnectionOptions): QueueOwnedConnection;
21
+ }
5
22
  /**
6
23
  * Lifecycle-managed queue runtime for worker discovery and job dispatch.
7
24
  *
@@ -10,21 +27,27 @@ import type { NormalizedQueueModuleOptions, Queue } from './types.js';
10
27
  */
11
28
  export declare class QueueLifecycleService implements Queue, OnApplicationBootstrap, OnApplicationShutdown, OnModuleDestroy {
12
29
  private readonly options;
30
+ private readonly redisClient;
13
31
  private readonly runtimeContainer;
14
32
  private readonly compiledModules;
15
33
  private readonly logger;
16
34
  private readonly bootstrapReadySignal;
35
+ private readonly moduleContext;
17
36
  private readonly descriptorsByJobType;
18
37
  private readonly queuesByJobName;
19
38
  private readonly workersByJobName;
20
39
  private readonly ownedConnections;
21
40
  private readonly deadLetterManager;
22
41
  private readonly readyWorkers;
42
+ private readonly runningWorkerJobNames;
43
+ private readonly failedWorkerJobNames;
44
+ private readonly workerStartFailures;
45
+ private readonly compiledModulesByType;
23
46
  private lifecycleState;
24
- private redisClient;
25
47
  private startPromise;
26
48
  private shutdownPromise;
27
- constructor(options: NormalizedQueueModuleOptions, runtimeContainer: Container, compiledModules: readonly CompiledModule[], logger: ApplicationLogger, bootstrapReadySignal?: BootstrapReadySignal);
49
+ private startupFailureRollbackPromise;
50
+ constructor(options: NormalizedQueueModuleOptions, redisClient: QueueRedisClient, runtimeContainer: Container, compiledModules: readonly CompiledModule[], logger: ApplicationLogger, bootstrapReadySignal?: BootstrapReadySignal, moduleContext?: QueueModuleContext);
28
51
  onApplicationBootstrap(): Promise<void>;
29
52
  onApplicationShutdown(): Promise<void>;
30
53
  onModuleDestroy(): Promise<void>;
@@ -37,14 +60,30 @@ export declare class QueueLifecycleService implements Queue, OnApplicationBootst
37
60
  * @throws {Error} When no worker is registered for the job type or the queue is not initialized.
38
61
  */
39
62
  enqueue<TJob extends object>(job: TJob): Promise<string>;
63
+ /**
64
+ * Reads a bounded snapshot of dead-letter records for one queue job name.
65
+ *
66
+ * Inspection reads Redis without starting workers or lifecycle-gating the read. The backing Redis client must
67
+ * remain reachable; `RedisModule` owns that shared client's shutdown.
68
+ *
69
+ * @param jobName Queue worker job name whose dead letters should be inspected.
70
+ * @param options Optional bounded inspection settings.
71
+ * @returns Valid records in newest-first order plus the malformed count for the inspected window.
72
+ * @throws The backing Redis read error when that client is unavailable or already shut down.
73
+ */
74
+ inspectDeadLetters(jobName: string, options?: QueueDeadLetterInspectionOptions): Promise<QueueDeadLetterInspectionResult>;
40
75
  /**
41
76
  * Creates a platform status snapshot for health checks and diagnostics.
42
77
  *
43
78
  * @returns A structured snapshot describing lifecycle state, discovered workers, and pending dead-letter writes.
44
79
  */
45
- createPlatformStatusSnapshot(): import("./status.js").QueuePlatformStatusSnapshot;
80
+ createPlatformStatusSnapshot(): QueuePlatformStatusSnapshot;
46
81
  private ensureStarted;
47
82
  private startLifecycle;
83
+ private shouldDiscoverWorkersInModule;
84
+ private canReachQueueRegistration;
85
+ private exportsQueueRegistration;
86
+ private assertUniqueQueueScope;
48
87
  private handleStartupFailure;
49
88
  private resolveRedisClient;
50
89
  private getRedisClient;
@@ -58,16 +97,22 @@ export declare class QueueLifecycleService implements Queue, OnApplicationBootst
58
97
  private registerInitializedWorker;
59
98
  private scheduleReadyWorkers;
60
99
  private runWorker;
100
+ private markWorkerReadyWhenStarted;
101
+ private recordWorkerStartFailure;
102
+ private rollbackAfterWorkerStartupFailure;
103
+ private toErrorMessage;
61
104
  private cleanupWorkerInitializationFailure;
62
105
  private createOwnedConnection;
63
106
  private executeWorker;
64
107
  private resolveWorkerHandler;
65
108
  private rehydrateWorkerPayload;
66
109
  private shutdown;
110
+ private waitForStartupFailureRollback;
67
111
  private waitForInFlightStartup;
68
112
  private closeInitializedResources;
69
113
  private tryCloseWorker;
70
114
  private tryCloseQueue;
71
115
  private tryCloseOwnedConnection;
72
116
  }
117
+ export {};
73
118
  //# sourceMappingURL=service.d.ts.map
@@ -1 +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,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAQlC,OAAO,KAAK,EACV,4BAA4B,EAC5B,KAAK,EAIN,MAAM,YAAY,CAAC;AAqHpB;;;;;GAKG;AACH,qBACa,qBAAsB,YAAW,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,eAAe;IAa/G,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAhBvC,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,QAAQ,CAAC,YAAY,CAAqB;IAClD,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,EACzB,oBAAoB,GAAE,oBAAuD;IAK1F,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;IA2B9D;;;;OAIG;IACH,4BAA4B;YAYd,aAAa;YAwBb,cAAc;YAgBd,oBAAoB;YASpB,kBAAkB;IAgBhC,OAAO,CAAC,cAAc;YAQR,iBAAiB;YAOjB,yBAAyB;IAyBvC,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,0BAA0B;IAkBlC,OAAO,CAAC,0BAA0B;IASlC,OAAO,CAAC,yBAAyB;IAUjC,OAAO,CAAC,oBAAoB;IAwB5B,OAAO,CAAC,SAAS;YAgBH,kCAAkC;YAkBlC,qBAAqB;YAiBrB,aAAa;YAOb,oBAAoB;IAyBlC,OAAO,CAAC,sBAAsB;YAQhB,QAAQ;YAyBR,sBAAsB;YAgBtB,yBAAyB;YAsBzB,cAAc;YAkBd,aAAa;YAQb,uBAAuB;CAOtC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EAEd,sBAAsB,EACtB,qBAAqB,EACrB,eAAe,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAiE,KAAK,iBAAiB,EAAoB,MAAM,QAAQ,CAAC;AAEjI,OAAO,EAA0B,KAAK,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAEnG,OAAO,EAGL,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,KAAK,EACV,4BAA4B,EAC5B,KAAK,EAEL,gCAAgC,EAChC,+BAA+B,EAGhC,MAAM,YAAY,CAAC;AAOpB,KAAK,oBAAoB,GAAG,iBAAiB,GAAG;IAC9C,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,IAAI,IAAI,CAAC;IACnB,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,UAAU,4BAA4B;IACpC,oBAAoB,EAAE,IAAI,CAAC;CAC5B;AAYD,UAAU,gBAAiB,SAAQ,0BAA0B;IAC3D,SAAS,CAAC,OAAO,CAAC,EAAE,4BAA4B,GAAG,oBAAoB,CAAC;CACzE;AAiID;;;;;GAKG;AACH,qBAAa,qBAAsB,YAAW,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,eAAe;IAiB/G,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAtBhC,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,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAqB;IAC3D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqB;IAC1D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA4B;IAChE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA0C;IAChF,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,6BAA6B,CAA4B;gBAG9C,OAAO,EAAE,4BAA4B,EACrC,WAAW,EAAE,gBAAgB,EAC7B,gBAAgB,EAAE,SAAS,EAC3B,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,MAAM,EAAE,iBAAiB,EACzB,oBAAoB,GAAE,oBAAuD,EAC7E,aAAa,GAAE,kBAA4E;IAOxG,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;IA2B9D;;;;;;;;;;OAUG;IACG,kBAAkB,CACtB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gCAAgC,GACzC,OAAO,CAAC,+BAA+B,CAAC;IAI3C;;;;OAIG;IACH,4BAA4B,IAAI,2BAA2B;YAgB7C,aAAa;YAwBb,cAAc;IAoB5B,OAAO,CAAC,6BAA6B;IAQrC,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,sBAAsB;YAUhB,oBAAoB;IASlC,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,cAAc;YAIR,iBAAiB;YAOjB,yBAAyB;IAyBvC,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,0BAA0B;IAkBlC,OAAO,CAAC,0BAA0B;IASlC,OAAO,CAAC,yBAAyB;IAUjC,OAAO,CAAC,oBAAoB;IAuC5B,OAAO,CAAC,SAAS;YA+BH,0BAA0B;IAkBxC,OAAO,CAAC,wBAAwB;IA6BhC,OAAO,CAAC,iCAAiC;IAgBzC,OAAO,CAAC,cAAc;YAIR,kCAAkC;YAkBlC,qBAAqB;YAiBrB,aAAa;YAOb,oBAAoB;IAyBlC,OAAO,CAAC,sBAAsB;YAQhB,QAAQ;YAyBR,6BAA6B;YAS7B,sBAAsB;YAgBtB,yBAAyB;YAuBzB,cAAc;YAkBd,aAAa;YAQb,uBAAuB;CAOtC"}
package/dist/service.js CHANGED
@@ -1,18 +1,10 @@
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';
11
3
  import { Queue as BullQueue, Worker as BullWorker } from 'bullmq';
12
4
  import { QueueDeadLetterManager } from './dead-letter-manager.js';
13
5
  import { normalizePositiveInteger, withTimeout } from './helpers.js';
14
6
  import { createQueuePlatformStatusSnapshot } from './status.js';
15
- import { QUEUE_OPTIONS } from './tokens.js';
7
+ import { getQueueLifecycleServiceToken, getQueueToken, QUEUE } from './tokens.js';
16
8
  import { discoverQueueWorkerDescriptors } from './worker-discovery.js';
17
9
  const IMMEDIATE_BOOTSTRAP_READY_SIGNAL = {
18
10
  wait: () => Promise.resolve()
@@ -22,7 +14,7 @@ function hasQueueRedisClient(value) {
22
14
  return false;
23
15
  }
24
16
  const client = value;
25
- return typeof client.duplicate === 'function' && typeof client.rpush === 'function' && typeof client.ltrim === 'function';
17
+ return typeof client.duplicate === 'function' && typeof client.lrange === 'function' && typeof client.rpush === 'function' && typeof client.ltrim === 'function';
26
18
  }
27
19
  function isQueuePayload(value) {
28
20
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -46,6 +38,27 @@ function toBullBackoff(backoff) {
46
38
  type: backoff.type ?? 'fixed'
47
39
  };
48
40
  }
41
+ function isQueueModuleContext(value) {
42
+ if (typeof value !== 'object' || value === null) {
43
+ return false;
44
+ }
45
+ const context = value;
46
+ return typeof context.moduleType === 'function' && typeof context.scope === 'string';
47
+ }
48
+ function collectQueueModuleScopeCount(compiledModules, scope) {
49
+ let count = 0;
50
+ for (const compiledModule of compiledModules) {
51
+ for (const provider of compiledModule.definition.providers ?? []) {
52
+ if (typeof provider !== 'object' || provider === null || !('useValue' in provider)) {
53
+ continue;
54
+ }
55
+ if (isQueueModuleContext(provider.useValue) && provider.useValue.scope === scope) {
56
+ count += 1;
57
+ }
58
+ }
59
+ }
60
+ return count;
61
+ }
49
62
  async function closeConnection(connection) {
50
63
  if (connection.status === 'end') {
51
64
  return;
@@ -66,28 +79,35 @@ async function closeConnection(connection) {
66
79
  * The service discovers `@QueueWorker()` providers during bootstrap, creates the
67
80
  * BullMQ queues/workers they require, and shuts them down with the application.
68
81
  */
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
- }
82
+ export class QueueLifecycleService {
74
83
  descriptorsByJobType = new Map();
75
84
  queuesByJobName = new Map();
76
85
  workersByJobName = new Map();
77
86
  ownedConnections = [];
78
87
  deadLetterManager;
79
88
  readyWorkers = [];
89
+ runningWorkerJobNames = new Set();
90
+ failedWorkerJobNames = new Set();
91
+ workerStartFailures = [];
92
+ compiledModulesByType;
80
93
  lifecycleState = 'idle';
81
- redisClient;
82
94
  startPromise;
83
95
  shutdownPromise;
84
- constructor(options, runtimeContainer, compiledModules, logger, bootstrapReadySignal = IMMEDIATE_BOOTSTRAP_READY_SIGNAL) {
96
+ startupFailureRollbackPromise;
97
+ constructor(options, redisClient, runtimeContainer, compiledModules, logger, bootstrapReadySignal = IMMEDIATE_BOOTSTRAP_READY_SIGNAL, moduleContext = {
98
+ moduleType: QueueLifecycleService,
99
+ scope: 'default'
100
+ }) {
85
101
  this.options = options;
102
+ this.redisClient = redisClient;
86
103
  this.runtimeContainer = runtimeContainer;
87
104
  this.compiledModules = compiledModules;
88
105
  this.logger = logger;
89
106
  this.bootstrapReadySignal = bootstrapReadySignal;
107
+ this.moduleContext = moduleContext;
108
+ this.compiledModulesByType = new Map(this.compiledModules.map(compiledModule => [compiledModule.type, compiledModule]));
90
109
  this.deadLetterManager = new QueueDeadLetterManager(this.options, this.logger, () => this.getRedisClient());
110
+ this.assertUniqueQueueScope();
91
111
  }
92
112
  async onApplicationBootstrap() {
93
113
  await this.ensureStarted();
@@ -127,27 +147,47 @@ class QueueLifecycleService {
127
147
  return queuedJob.id ?? '';
128
148
  }
129
149
 
150
+ /**
151
+ * Reads a bounded snapshot of dead-letter records for one queue job name.
152
+ *
153
+ * Inspection reads Redis without starting workers or lifecycle-gating the read. The backing Redis client must
154
+ * remain reachable; `RedisModule` owns that shared client's shutdown.
155
+ *
156
+ * @param jobName Queue worker job name whose dead letters should be inspected.
157
+ * @param options Optional bounded inspection settings.
158
+ * @returns Valid records in newest-first order plus the malformed count for the inspected window.
159
+ * @throws The backing Redis read error when that client is unavailable or already shut down.
160
+ */
161
+ async inspectDeadLetters(jobName, options) {
162
+ return this.deadLetterManager.inspect(jobName, options);
163
+ }
164
+
130
165
  /**
131
166
  * Creates a platform status snapshot for health checks and diagnostics.
132
167
  *
133
168
  * @returns A structured snapshot describing lifecycle state, discovered workers, and pending dead-letter writes.
134
169
  */
135
170
  createPlatformStatusSnapshot() {
171
+ const lastWorkerStartFailure = this.workerStartFailures[this.workerStartFailures.length - 1];
136
172
  return createQueuePlatformStatusSnapshot({
137
173
  dependencyId: getRedisComponentId(this.options.clientName),
138
174
  lifecycleState: this.lifecycleState,
175
+ ...(lastWorkerStartFailure ? {
176
+ lastWorkerStartFailure: lastWorkerStartFailure.message
177
+ } : {}),
139
178
  pendingDeadLetterWrites: this.deadLetterManager.pendingWriteCount,
140
179
  queuesReady: this.queuesByJobName.size,
180
+ workerStartFailures: this.workerStartFailures.length,
141
181
  workerShutdownTimeoutMs: this.options.workerShutdownTimeoutMs,
142
182
  workersDiscovered: this.descriptorsByJobType.size,
143
- workersReady: this.workersByJobName.size
183
+ workersReady: this.runningWorkerJobNames.size
144
184
  });
145
185
  }
146
186
  async ensureStarted() {
147
187
  if (this.lifecycleState === 'started') {
148
188
  return;
149
189
  }
150
- if (this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') {
190
+ if (this.lifecycleState === 'failed' || this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') {
151
191
  throw new Error(`Queue lifecycle state is ${this.lifecycleState}.`);
152
192
  }
153
193
  if (!this.startPromise) {
@@ -163,10 +203,9 @@ class QueueLifecycleService {
163
203
  this.startPromise = undefined;
164
204
  }
165
205
  async startLifecycle() {
166
- const redis = await this.resolveRedisClient();
167
- this.redisClient = redis;
206
+ const redis = this.resolveRedisClient();
168
207
  this.descriptorsByJobType.clear();
169
- for (const [jobType, descriptor] of discoverQueueWorkerDescriptors(this.compiledModules, this.options, this.logger)) {
208
+ for (const [jobType, descriptor] of discoverQueueWorkerDescriptors(this.compiledModules, this.options, this.logger, compiledModule => this.shouldDiscoverWorkersInModule(compiledModule))) {
170
209
  this.descriptorsByJobType.set(jobType, descriptor);
171
210
  }
172
211
  await this.initializeWorkers(redis);
@@ -175,29 +214,55 @@ class QueueLifecycleService {
175
214
  this.scheduleReadyWorkers();
176
215
  }
177
216
  }
217
+ shouldDiscoverWorkersInModule(compiledModule) {
218
+ if (this.options.global) {
219
+ return true;
220
+ }
221
+ return this.canReachQueueRegistration(compiledModule);
222
+ }
223
+ canReachQueueRegistration(compiledModule, visited = new Set()) {
224
+ if (visited.has(compiledModule.type)) {
225
+ return false;
226
+ }
227
+ visited.add(compiledModule.type);
228
+ for (const importedModuleType of compiledModule.definition.imports ?? []) {
229
+ if (importedModuleType === this.moduleContext.moduleType) {
230
+ return true;
231
+ }
232
+ const importedModule = this.compiledModulesByType.get(importedModuleType);
233
+ if (!importedModule || !this.exportsQueueRegistration(importedModule)) {
234
+ continue;
235
+ }
236
+ if (this.canReachQueueRegistration(importedModule, visited)) {
237
+ return true;
238
+ }
239
+ }
240
+ return false;
241
+ }
242
+ exportsQueueRegistration(compiledModule) {
243
+ return compiledModule.exportedTokens.has(QueueLifecycleService) || compiledModule.exportedTokens.has(QUEUE) || compiledModule.exportedTokens.has(getQueueLifecycleServiceToken(this.options.scope)) || compiledModule.exportedTokens.has(getQueueToken(this.options.scope));
244
+ }
245
+ assertUniqueQueueScope() {
246
+ const scopeCount = collectQueueModuleScopeCount(this.compiledModules, this.moduleContext.scope);
247
+ if (scopeCount > 1) {
248
+ throw new Error(`Duplicate @fluojs/queue scope "${this.moduleContext.scope}" registered. Provide a unique QueueModule.forRoot({ scope }) value for each scoped queue registration.`);
249
+ }
250
+ }
178
251
  async handleStartupFailure() {
179
252
  await this.closeInitializedResources();
253
+ await this.deadLetterManager.drainPendingWrites();
180
254
  if (this.lifecycleState === 'starting') {
181
255
  this.lifecycleState = 'idle';
182
256
  }
183
- this.redisClient = undefined;
184
257
  this.startPromise = undefined;
185
258
  }
186
- async resolveRedisClient() {
187
- const redisToken = getRedisClientToken(this.options.clientName);
188
- if (!this.runtimeContainer.has(redisToken)) {
189
- throw new Error('@fluojs/queue requires a registered Redis client with duplicate(), rpush(), and ltrim() methods.');
259
+ resolveRedisClient() {
260
+ if (!hasQueueRedisClient(this.redisClient)) {
261
+ throw new Error('@fluojs/queue requires a Redis client with duplicate(), lrange(), rpush(), and ltrim() methods.');
190
262
  }
191
- const redisClient = await this.runtimeContainer.resolve(redisToken);
192
- if (!hasQueueRedisClient(redisClient)) {
193
- throw new Error('@fluojs/queue requires a Redis client with duplicate(), rpush(), and ltrim() methods.');
194
- }
195
- return redisClient;
263
+ return this.redisClient;
196
264
  }
197
265
  getRedisClient() {
198
- if (!this.redisClient) {
199
- throw new Error('@fluojs/queue Redis client is not initialized.');
200
- }
201
266
  return this.redisClient;
202
267
  }
203
268
  async initializeWorkers(redis) {
@@ -278,23 +343,92 @@ class QueueLifecycleService {
278
343
  descriptor,
279
344
  worker
280
345
  } of workers) {
346
+ if (this.lifecycleState !== 'started') {
347
+ break;
348
+ }
281
349
  this.runWorker(descriptor, worker);
350
+ if (this.lifecycleState !== 'started') {
351
+ break;
352
+ }
282
353
  }
283
354
  }).catch(error => {
284
355
  if (this.lifecycleState !== 'started') {
285
356
  return;
286
357
  }
358
+ this.lifecycleState = 'failed';
359
+ this.workerStartFailures.push({
360
+ jobName: '*',
361
+ message: this.toErrorMessage(error),
362
+ workerName: 'bootstrap-ready-signal'
363
+ });
287
364
  this.logger.error('Failed to start queue workers after application bootstrap readiness.', error, 'QueueLifecycleService');
365
+ this.rollbackAfterWorkerStartupFailure();
288
366
  });
289
367
  }
290
368
  runWorker(descriptor, worker) {
291
369
  const runnableWorker = worker;
292
370
  if (typeof runnableWorker.run !== 'function') {
371
+ this.recordWorkerStartFailure(descriptor, new Error(`Queue worker ${descriptor.workerName} cannot start because BullMQ Worker.run() is unavailable.`));
372
+ return;
373
+ }
374
+ let runResult;
375
+ try {
376
+ runResult = runnableWorker.run();
377
+ } catch (error) {
378
+ this.recordWorkerStartFailure(descriptor, error);
379
+ return;
380
+ }
381
+ const runPromise = Promise.resolve(runResult);
382
+ void runPromise.catch(error => {
383
+ this.recordWorkerStartFailure(descriptor, error);
384
+ });
385
+ void this.markWorkerReadyWhenStarted(descriptor, runnableWorker, runPromise).catch(error => {
386
+ this.recordWorkerStartFailure(descriptor, error);
387
+ });
388
+ }
389
+ async markWorkerReadyWhenStarted(descriptor, worker, runPromise) {
390
+ if (typeof worker.waitUntilReady === 'function') {
391
+ await Promise.race([worker.waitUntilReady(), runPromise]);
392
+ } else {
393
+ await Promise.race([Promise.resolve(), runPromise]);
394
+ }
395
+ if (this.lifecycleState !== 'started' || this.failedWorkerJobNames.has(descriptor.jobName)) {
396
+ return;
397
+ }
398
+ this.runningWorkerJobNames.add(descriptor.jobName);
399
+ }
400
+ recordWorkerStartFailure(descriptor, error) {
401
+ if (this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') {
293
402
  return;
294
403
  }
295
- void Promise.resolve(runnableWorker.run()).catch(error => {
296
- this.logger.error(`Failed to start queue worker ${descriptor.workerName} after application bootstrap.`, error, 'QueueLifecycleService');
404
+ if (this.failedWorkerJobNames.has(descriptor.jobName)) {
405
+ return;
406
+ }
407
+ this.failedWorkerJobNames.add(descriptor.jobName);
408
+ this.runningWorkerJobNames.delete(descriptor.jobName);
409
+ this.workerStartFailures.push({
410
+ jobName: descriptor.jobName,
411
+ message: this.toErrorMessage(error),
412
+ workerName: descriptor.workerName
297
413
  });
414
+ if (this.lifecycleState === 'started' || this.lifecycleState === 'starting') {
415
+ this.lifecycleState = 'failed';
416
+ }
417
+ this.logger.error(`Failed to start queue worker ${descriptor.workerName} after application bootstrap.`, error, 'QueueLifecycleService');
418
+ this.rollbackAfterWorkerStartupFailure();
419
+ }
420
+ rollbackAfterWorkerStartupFailure() {
421
+ if (!this.startupFailureRollbackPromise) {
422
+ this.startupFailureRollbackPromise = (async () => {
423
+ await this.closeInitializedResources();
424
+ await this.deadLetterManager.drainPendingWrites();
425
+ })().catch(rollbackError => {
426
+ this.logger.error('Failed to roll back queue resources after worker startup failure.', rollbackError, 'QueueLifecycleService');
427
+ });
428
+ }
429
+ }
430
+ toErrorMessage(error) {
431
+ return error instanceof Error ? error.message : String(error);
298
432
  }
299
433
  async cleanupWorkerInitializationFailure(resources) {
300
434
  if (resources.worker) {
@@ -362,14 +496,21 @@ class QueueLifecycleService {
362
496
  this.lifecycleState = 'stopping';
363
497
  this.shutdownPromise = (async () => {
364
498
  await this.waitForInFlightStartup();
499
+ await this.waitForStartupFailureRollback();
365
500
  await this.closeInitializedResources();
366
501
  await this.deadLetterManager.drainPendingWrites();
367
502
  this.lifecycleState = 'stopped';
368
- this.redisClient = undefined;
369
503
  this.startPromise = undefined;
370
504
  })();
371
505
  await this.shutdownPromise;
372
506
  }
507
+ async waitForStartupFailureRollback() {
508
+ if (!this.startupFailureRollbackPromise) {
509
+ return;
510
+ }
511
+ await this.startupFailureRollbackPromise;
512
+ this.startupFailureRollbackPromise = undefined;
513
+ }
373
514
  async waitForInFlightStartup() {
374
515
  const startup = this.startPromise;
375
516
  if (!startup) {
@@ -390,6 +531,7 @@ class QueueLifecycleService {
390
531
  this.workersByJobName.clear();
391
532
  this.queuesByJobName.clear();
392
533
  this.readyWorkers.splice(0);
534
+ this.runningWorkerJobNames.clear();
393
535
  for (const worker of workers) {
394
536
  await this.tryCloseWorker(worker);
395
537
  }
@@ -426,8 +568,4 @@ class QueueLifecycleService {
426
568
  this.logger.error('Failed to close queue-owned Redis connection during shutdown.', error, 'QueueLifecycleService');
427
569
  }
428
570
  }
429
- static {
430
- _initClass();
431
- }
432
- }
433
- export { _QueueLifecycleServic as QueueLifecycleService };
571
+ }
package/dist/status.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  import type { PlatformHealthReport, PlatformReadinessReport, PlatformSnapshot } from '@fluojs/runtime';
2
2
  /** Lifecycle phases reported by the queue platform status adapter. */
3
- export type QueueLifecycleState = 'idle' | 'starting' | 'started' | 'stopping' | 'stopped';
3
+ export type QueueLifecycleState = 'idle' | 'starting' | 'started' | 'stopping' | 'stopped' | 'failed';
4
4
  /** Input payload used to derive queue readiness, health, and dependency details. */
5
5
  export interface QueueStatusAdapterInput {
6
6
  dependencyId?: string;
7
+ lastWorkerStartFailure?: string;
7
8
  lifecycleState: QueueLifecycleState;
8
9
  pendingDeadLetterWrites: number;
9
10
  queuesReady: number;
11
+ workerStartFailures?: number;
10
12
  workerShutdownTimeoutMs: number;
11
13
  workersDiscovered: number;
12
14
  workersReady: number;
@@ -1 +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,uBAAuB,EAAE,MAAM,CAAC;IAChC,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,CAmB7G"}
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,GAAG,QAAQ,CAAC;AAEtG,oFAAoF;AACpF,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,mBAAmB,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uBAAuB,EAAE,MAAM,CAAC;IAChC,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;AAoHD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,uBAAuB,GAAG,2BAA2B,CAuB7G"}