@dudousxd/nestjs-durable 0.48.0 → 0.48.2

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/index.d.cts CHANGED
@@ -602,6 +602,18 @@ interface DurableModuleOptions {
602
602
  * a driving instance's poll picks it up. Ignored (irrelevant) for a thin worker (no `store`).
603
603
  */
604
604
  drive?: boolean;
605
+ /**
606
+ * Whether this process CONSUMES from the broker. Defaults to `true`. Set `false` in a process that
607
+ * boots the module without being a worker — a CLI command, a REPL, a migration or seed script — so
608
+ * it doesn't compete with the real fleet: every transport that supports it (`BullMQTransport`) has
609
+ * its point-to-point consumers (step tasks, results, decisions, step events, start-run, run-request)
610
+ * parked via `deferConsumers()`, and no co-located/thin worker consumer starts. The process still
611
+ * dispatches and starts runs; the jobs stay on the queues for the fleet. Pair it with
612
+ * `drive: false` so it doesn't poll/recover runs either. To consume later in the same process, call
613
+ * `startConsumers()` on your transport. A transport without `deferConsumers()` (the SQL/SQS/in-process
614
+ * transports) keeps consuming — a warning says so.
615
+ */
616
+ consumers?: boolean;
605
617
  /** Max ms to wait for in-flight runs on shutdown before exiting. Defaults to 10000. Operator only. */
606
618
  shutdownTimeoutMs?: number;
607
619
  /**
@@ -817,6 +829,7 @@ declare class DurableStartClient {
817
829
  resume(_runId: string): Promise<void>;
818
830
  waitForRun(_runId: string, _opts?: {
819
831
  timeoutMs?: number;
832
+ until?: 'settled' | 'terminal';
820
833
  }): Promise<void>;
821
834
  signal(_token: string, _payload: unknown): Promise<void>;
822
835
  signalWithStart(_workflow: string, _input: unknown, _runId: string, _signal: {
@@ -1266,9 +1279,12 @@ declare class WorkflowService {
1266
1279
  * Resolve once a run settles — terminal (completed/failed/cancelled/dead) or suspended. `start`
1267
1280
  * only enqueues (a worker runs the body), so pair them when a request needs the outcome:
1268
1281
  * `const { runId } = await svc.start(...); const result = await svc.waitForRun(runId)`.
1282
+ * `until: 'terminal'` waits past suspensions until the run completes/fails/is cancelled — what a
1283
+ * delayed start (`opts.startAt`) needs, since it is `suspended` until its timer fires.
1269
1284
  */
1270
1285
  waitForRun(runId: string, opts?: {
1271
1286
  timeoutMs?: number;
1287
+ until?: 'settled' | 'terminal';
1272
1288
  }): Promise<RunResult>;
1273
1289
  /** Deliver an external signal (e.g. from a webhook) to the run waiting on `token`. */
1274
1290
  signal(token: string, payload: unknown): Promise<RunResult | null>;
package/dist/index.d.ts CHANGED
@@ -602,6 +602,18 @@ interface DurableModuleOptions {
602
602
  * a driving instance's poll picks it up. Ignored (irrelevant) for a thin worker (no `store`).
603
603
  */
604
604
  drive?: boolean;
605
+ /**
606
+ * Whether this process CONSUMES from the broker. Defaults to `true`. Set `false` in a process that
607
+ * boots the module without being a worker — a CLI command, a REPL, a migration or seed script — so
608
+ * it doesn't compete with the real fleet: every transport that supports it (`BullMQTransport`) has
609
+ * its point-to-point consumers (step tasks, results, decisions, step events, start-run, run-request)
610
+ * parked via `deferConsumers()`, and no co-located/thin worker consumer starts. The process still
611
+ * dispatches and starts runs; the jobs stay on the queues for the fleet. Pair it with
612
+ * `drive: false` so it doesn't poll/recover runs either. To consume later in the same process, call
613
+ * `startConsumers()` on your transport. A transport without `deferConsumers()` (the SQL/SQS/in-process
614
+ * transports) keeps consuming — a warning says so.
615
+ */
616
+ consumers?: boolean;
605
617
  /** Max ms to wait for in-flight runs on shutdown before exiting. Defaults to 10000. Operator only. */
606
618
  shutdownTimeoutMs?: number;
607
619
  /**
@@ -817,6 +829,7 @@ declare class DurableStartClient {
817
829
  resume(_runId: string): Promise<void>;
818
830
  waitForRun(_runId: string, _opts?: {
819
831
  timeoutMs?: number;
832
+ until?: 'settled' | 'terminal';
820
833
  }): Promise<void>;
821
834
  signal(_token: string, _payload: unknown): Promise<void>;
822
835
  signalWithStart(_workflow: string, _input: unknown, _runId: string, _signal: {
@@ -1266,9 +1279,12 @@ declare class WorkflowService {
1266
1279
  * Resolve once a run settles — terminal (completed/failed/cancelled/dead) or suspended. `start`
1267
1280
  * only enqueues (a worker runs the body), so pair them when a request needs the outcome:
1268
1281
  * `const { runId } = await svc.start(...); const result = await svc.waitForRun(runId)`.
1282
+ * `until: 'terminal'` waits past suspensions until the run completes/fails/is cancelled — what a
1283
+ * delayed start (`opts.startAt`) needs, since it is `suspended` until its timer fires.
1269
1284
  */
1270
1285
  waitForRun(runId: string, opts?: {
1271
1286
  timeoutMs?: number;
1287
+ until?: 'settled' | 'terminal';
1272
1288
  }): Promise<RunResult>;
1273
1289
  /** Deliver an external signal (e.g. from a webhook) to the run waiting on `token`. */
1274
1290
  signal(token: string, payload: unknown): Promise<RunResult | null>;
package/dist/index.js CHANGED
@@ -602,6 +602,7 @@ var ThinWorkerBootstrap = class {
602
602
  const options = this.options;
603
603
  const runtime = this.runtime;
604
604
  if (runtime === null || !isPureThinWorker(options) || options.connection === void 0) return;
605
+ if (options.consumers === false) return;
605
606
  const handle = await this.runRedisWorker({
606
607
  runtime,
607
608
  connection: options.connection,
@@ -980,6 +981,7 @@ var InAppWorkerBootstrap = class {
980
981
  const options = this.options;
981
982
  const runtime = this.runtime;
982
983
  if (runtime === null || !isCoLocatedWorker(options) || options.connection === void 0) return;
984
+ if (options.consumers === false) return;
983
985
  const handle = await this.runRedisWorker({
984
986
  runtime,
985
987
  connection: options.connection,
@@ -2425,6 +2427,8 @@ var WorkflowService = class {
2425
2427
  * Resolve once a run settles — terminal (completed/failed/cancelled/dead) or suspended. `start`
2426
2428
  * only enqueues (a worker runs the body), so pair them when a request needs the outcome:
2427
2429
  * `const { runId } = await svc.start(...); const result = await svc.waitForRun(runId)`.
2430
+ * `until: 'terminal'` waits past suspensions until the run completes/fails/is cancelled — what a
2431
+ * delayed start (`opts.startAt`) needs, since it is `suspended` until its timer fires.
2428
2432
  */
2429
2433
  waitForRun(runId, opts) {
2430
2434
  return this.engine.waitForRun(runId, opts);
@@ -2536,6 +2540,15 @@ function scopedStore(store, options) {
2536
2540
  });
2537
2541
  }
2538
2542
  __name(scopedStore, "scopedStore");
2543
+ function deferTransportConsumers(transport) {
2544
+ const deferrable = transport;
2545
+ if (typeof deferrable.deferConsumers === "function") {
2546
+ deferrable.deferConsumers();
2547
+ return;
2548
+ }
2549
+ console.warn(`[nestjs-durable] consumers: false \u2014 ${transport.constructor?.name ?? "this transport"} cannot defer its consumers and will keep consuming in this process`);
2550
+ }
2551
+ __name(deferTransportConsumers, "deferTransportConsumers");
2539
2552
  function assertValidRole(options) {
2540
2553
  const hasStore = options.store !== void 0;
2541
2554
  const hasConnection = options.connection !== void 0;
@@ -2762,6 +2775,14 @@ var DurableModule = class _DurableModule {
2762
2775
  const context = options.context ?? (accessor ? () => carrierFromAccessor(accessor) : void 0);
2763
2776
  const runtime = accessor ? await resolveContextRuntime() : void 0;
2764
2777
  const rehydrate = runtime && ((carrier, fn) => carrier && Object.keys(carrier).length > 0 ? runtime.deserialize(carrier, fn) : fn());
2778
+ if (options.consumers === false) {
2779
+ for (const t of [
2780
+ transport,
2781
+ ...(options.transports ?? []).map((n) => n.transport)
2782
+ ]) {
2783
+ if (t) deferTransportConsumers(t);
2784
+ }
2785
+ }
2765
2786
  const engine = new WorkflowEngine6({
2766
2787
  store,
2767
2788
  transport: transport ?? void 0,