@fluojs/queue 1.0.0-beta.3 → 1.0.0-beta.5

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/README.ko.md CHANGED
@@ -59,30 +59,30 @@ import { Module, Inject } from '@fluojs/core';
59
59
  import { QueueModule, QueueLifecycleService } from '@fluojs/queue';
60
60
  import { RedisModule } from '@fluojs/redis';
61
61
 
62
+ @Inject(QueueLifecycleService)
63
+ export class OrderService {
64
+ constructor(private readonly queue: QueueLifecycleService) {}
65
+
66
+ async placeOrder(id: string) {
67
+ await this.queue.enqueue(new ProcessOrderJob(id));
68
+ }
69
+ }
70
+
62
71
  @Module({
63
72
  imports: [
64
73
  RedisModule.forRoot({ host: 'localhost', port: 6379 }),
65
74
  QueueModule.forRoot(),
66
75
  ],
67
- providers: [OrderWorker],
76
+ providers: [OrderService, OrderWorker],
68
77
  })
69
78
  export class AppModule {}
70
-
71
- export class OrderService {
72
- @Inject(QueueLifecycleService)
73
- private readonly queue: QueueLifecycleService;
74
-
75
- async placeOrder(id: string) {
76
- await this.queue.enqueue(new ProcessOrderJob(id));
77
- }
78
- }
79
79
  ```
80
80
 
81
81
  ## 일반적인 패턴
82
82
 
83
83
  ### 이름 있는 Redis 클라이언트
84
84
 
85
- `clientName`을 생략하면 애플리케이션의 기본 `@fluojs/redis` 클라이언트를 계속 사용합니다. 큐가 기본 Redis 대신 다른 연결을 사용해야 한다면 `RedisModule.forRootNamed(...)`로 등록한 이름을 `clientName`에 지정하세요.
85
+ `clientName`을 생략하면 애플리케이션의 기본 `@fluojs/redis` 클라이언트를 계속 사용합니다. 큐가 기본 Redis 대신 다른 연결을 사용해야 한다면 `RedisModule.forRoot({ name, ... })`로 등록한 이름을 `clientName`에 지정하세요.
86
86
 
87
87
  ```typescript
88
88
  QueueModule.forRoot({ clientName: 'jobs' })
package/README.md CHANGED
@@ -59,30 +59,30 @@ import { Module, Inject } from '@fluojs/core';
59
59
  import { QueueModule, QueueLifecycleService } from '@fluojs/queue';
60
60
  import { RedisModule } from '@fluojs/redis';
61
61
 
62
+ @Inject(QueueLifecycleService)
63
+ export class OrderService {
64
+ constructor(private readonly queue: QueueLifecycleService) {}
65
+
66
+ async placeOrder(id: string) {
67
+ await this.queue.enqueue(new ProcessOrderJob(id));
68
+ }
69
+ }
70
+
62
71
  @Module({
63
72
  imports: [
64
73
  RedisModule.forRoot({ host: 'localhost', port: 6379 }),
65
74
  QueueModule.forRoot(),
66
75
  ],
67
- providers: [OrderWorker],
76
+ providers: [OrderService, OrderWorker],
68
77
  })
69
78
  export class AppModule {}
70
-
71
- export class OrderService {
72
- @Inject(QueueLifecycleService)
73
- private readonly queue: QueueLifecycleService;
74
-
75
- async placeOrder(id: string) {
76
- await this.queue.enqueue(new ProcessOrderJob(id));
77
- }
78
- }
79
79
  ```
80
80
 
81
81
  ## Common Patterns
82
82
 
83
83
  ### Named Redis Client
84
84
 
85
- Leave `clientName` unset to keep using the default `@fluojs/redis` client from your app. If your queues should use a non-default Redis connection, set `clientName` to the name registered with `RedisModule.forRootNamed(...)`.
85
+ Leave `clientName` unset to keep using the default `@fluojs/redis` client from your app. If your queues should use a non-default Redis connection, set `clientName` to the name registered with `RedisModule.forRoot({ name, ... })`.
86
86
 
87
87
  ```typescript
88
88
  QueueModule.forRoot({ clientName: 'jobs' })
package/dist/module.js CHANGED
@@ -58,7 +58,7 @@ export class QueueModule {
58
58
  class QueueModuleDefinition {}
59
59
  return defineModule(QueueModuleDefinition, {
60
60
  exports: [QueueLifecycleService, QUEUE],
61
- global: true,
61
+ global: options.global ?? true,
62
62
  providers: createQueueProviders(options)
63
63
  });
64
64
  }
package/dist/service.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Container } from '@fluojs/di';
2
- import { type ApplicationLogger, type CompiledModule, type OnApplicationBootstrap, type OnApplicationShutdown, type OnModuleDestroy } from '@fluojs/runtime';
2
+ import type { ApplicationLogger, CompiledModule, OnApplicationBootstrap, OnApplicationShutdown, OnModuleDestroy } from '@fluojs/runtime';
3
3
  import type { NormalizedQueueModuleOptions, Queue } from './types.js';
4
4
  /**
5
5
  * Lifecycle-managed queue runtime for worker discovery and job dispatch.
@@ -59,6 +59,7 @@ export declare class QueueLifecycleService implements Queue, OnApplicationBootst
59
59
  private resolveWorkerHandler;
60
60
  private rehydrateWorkerPayload;
61
61
  private shutdown;
62
+ private waitForInFlightStartup;
62
63
  private closeInitializedResources;
63
64
  private tryCloseWorker;
64
65
  private tryCloseQueue;
@@ -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,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;AAkGpB;;;;;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;YAiBrB,aAAa;YAOb,oBAAoB;IAyBlC,OAAO,CAAC,sBAAsB;YAQhB,QAAQ;YAsBR,yBAAyB;YAqBzB,cAAc;YAQd,aAAa;YAQb,uBAAuB;CAOtC"}
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;AASzB,OAAO,KAAK,EACV,4BAA4B,EAC5B,KAAK,EAIN,MAAM,YAAY,CAAC;AAkGpB;;;;;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;IA2B9D;;;;OAIG;IACH,4BAA4B;YAWd,aAAa;YAwBb,cAAc;YAed,oBAAoB;YASpB,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;YAiBrB,aAAa;YAOb,oBAAoB;IAyBlC,OAAO,CAAC,sBAAsB;YAQhB,QAAQ;YAyBR,sBAAsB;YAgBtB,yBAAyB;YAqBzB,cAAc;YAQd,aAAa;YAQb,uBAAuB;CAOtC"}
package/dist/service.js CHANGED
@@ -104,6 +104,9 @@ class QueueLifecycleService {
104
104
  */
105
105
  async enqueue(job) {
106
106
  await this.ensureStarted();
107
+ if (this.lifecycleState !== 'started') {
108
+ throw new Error(`Queue lifecycle state is ${this.lifecycleState}.`);
109
+ }
107
110
  const descriptor = this.descriptorsByJobType.get(job.constructor);
108
111
  if (!descriptor) {
109
112
  throw new Error(`No @QueueWorker() registered for job type ${job.constructor.name}.`);
@@ -161,11 +164,15 @@ class QueueLifecycleService {
161
164
  this.descriptorsByJobType.set(jobType, descriptor);
162
165
  }
163
166
  await this.initializeWorkers(redis);
164
- this.lifecycleState = 'started';
167
+ if (this.lifecycleState === 'starting') {
168
+ this.lifecycleState = 'started';
169
+ }
165
170
  }
166
171
  async handleStartupFailure() {
167
172
  await this.closeInitializedResources();
168
- this.lifecycleState = 'idle';
173
+ if (this.lifecycleState === 'starting') {
174
+ this.lifecycleState = 'idle';
175
+ }
169
176
  this.redisClient = undefined;
170
177
  this.startPromise = undefined;
171
178
  }
@@ -314,13 +321,28 @@ class QueueLifecycleService {
314
321
  }
315
322
  this.lifecycleState = 'stopping';
316
323
  this.shutdownPromise = (async () => {
324
+ await this.waitForInFlightStartup();
317
325
  await this.closeInitializedResources();
318
326
  await this.deadLetterManager.drainPendingWrites();
319
327
  this.lifecycleState = 'stopped';
328
+ this.redisClient = undefined;
320
329
  this.startPromise = undefined;
321
330
  })();
322
331
  await this.shutdownPromise;
323
332
  }
333
+ async waitForInFlightStartup() {
334
+ const startup = this.startPromise;
335
+ if (!startup) {
336
+ return;
337
+ }
338
+ try {
339
+ await startup;
340
+ } catch {
341
+ // ensureStarted() owns startup rollback and preserves the original
342
+ // bootstrap error. Shutdown still continues so partially registered
343
+ // resources cannot outlive the application lifecycle.
344
+ }
345
+ }
324
346
  async closeInitializedResources() {
325
347
  const workers = Array.from(this.workersByJobName.values());
326
348
  const queues = Array.from(this.queuesByJobName.values());
package/dist/types.d.ts CHANGED
@@ -31,6 +31,8 @@ export interface QueueWorkerOptions {
31
31
  /** Module-wide defaults used when individual workers omit execution settings. */
32
32
  export interface QueueModuleOptions {
33
33
  clientName?: string;
34
+ /** Whether queue providers should be visible globally. Defaults to `true`. */
35
+ global?: boolean;
34
36
  defaultAttempts?: number;
35
37
  defaultBackoff?: QueueBackoffOptions;
36
38
  defaultConcurrency?: number;
@@ -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,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;CAC9C;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;CAC9C;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":"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;CAC9C;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;CAC9C;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"}
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "redis",
11
11
  "dlq"
12
12
  ],
13
- "version": "1.0.0-beta.3",
13
+ "version": "1.0.0-beta.5",
14
14
  "private": false,
15
15
  "license": "MIT",
16
16
  "repository": {
@@ -38,10 +38,10 @@
38
38
  ],
39
39
  "dependencies": {
40
40
  "bullmq": "^5.58.0",
41
- "@fluojs/core": "^1.0.0-beta.4",
42
- "@fluojs/di": "^1.0.0-beta.6",
43
- "@fluojs/redis": "^1.0.0-beta.2",
44
- "@fluojs/runtime": "^1.0.0-beta.11"
41
+ "@fluojs/core": "^1.0.0-beta.5",
42
+ "@fluojs/di": "^1.0.0-beta.7",
43
+ "@fluojs/redis": "^1.0.0-beta.4",
44
+ "@fluojs/runtime": "^1.0.0-beta.12"
45
45
  },
46
46
  "devDependencies": {
47
47
  "vitest": "^3.2.4"