@dudousxd/nestjs-durable-core 0.55.1 → 0.57.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/index.d.cts CHANGED
@@ -1155,22 +1155,6 @@ interface Transport {
1155
1155
  onResult(handler: (result: StepResult) => Promise<void>): void;
1156
1156
  /** worker → engine: liveness signal for an in-flight long step. */
1157
1157
  onHeartbeat(handler: (beat: Heartbeat) => Promise<void>): void;
1158
- /**
1159
- * Partition this transport's queues/keys by `namespace` (matching the engine's store namespace), so
1160
- * multiple logical deployments can share one broker. Idempotent. An explicit namespace passed to the
1161
- * transport's constructor TAKES PRECEDENCE over this. No-op when `namespace === "default"`. Optional —
1162
- * transports that don't partition simply omit it.
1163
- */
1164
- useNamespace?(namespace: string): void;
1165
- /**
1166
- * A SIBLING transport on the same broker/connection, pinned to `namespace` (explicit — never
1167
- * re-scoped by a later {@link useNamespace}). Powers the tenant-worker bridge preset
1168
- * (`topology: { role: 'control-plane', tenant, tenantWorkers: 'bridge' }`): a tenant-scoped
1169
- * operator pairs its namespaced primary with `withNamespace('default')` — a bare-prefix sibling —
1170
- * so operator-convention tenant workers (`<group>@<tenant>` under the bare prefix) are
1171
- * discoverable and dispatchable. Optional — transports that don't partition simply omit it.
1172
- */
1173
- withNamespace?(namespace: string): Transport;
1174
1158
  /** Release the transport's resources (broker workers, queues, connections) for a clean shutdown.
1175
1159
  * Optional — an in-process transport has nothing to close. Called on `onApplicationShutdown`
1176
1160
  * after the engine drains, so a deploy hands off instead of leaving the broker to time out. */
@@ -3562,7 +3546,7 @@ declare function readSearchAttributes<S extends SearchAttributesSchema>(schema:
3562
3546
 
3563
3547
  /**
3564
3548
  * Compute the worker group a tenant's run dispatches to. Mirrors the transport's
3565
- * default-is-bare rule (see {@link TransportPool.useNamespace}'s `'default'` no-op): a
3549
+ * default-is-bare rule (unset/empty/`'default'` ⇒ bare): a
3566
3550
  * `tenant` of `undefined`, `''`, or `'default'` is the bare `baseGroup`, so a single-tenant
3567
3551
  * deployment (or the `'default'` tenant of a multi-tenant one) stays byte-identical to today.
3568
3552
  * Any other tenant suffixes the group as `<baseGroup>@<tenant>`, so an operator control plane
package/dist/index.d.ts CHANGED
@@ -1155,22 +1155,6 @@ interface Transport {
1155
1155
  onResult(handler: (result: StepResult) => Promise<void>): void;
1156
1156
  /** worker → engine: liveness signal for an in-flight long step. */
1157
1157
  onHeartbeat(handler: (beat: Heartbeat) => Promise<void>): void;
1158
- /**
1159
- * Partition this transport's queues/keys by `namespace` (matching the engine's store namespace), so
1160
- * multiple logical deployments can share one broker. Idempotent. An explicit namespace passed to the
1161
- * transport's constructor TAKES PRECEDENCE over this. No-op when `namespace === "default"`. Optional —
1162
- * transports that don't partition simply omit it.
1163
- */
1164
- useNamespace?(namespace: string): void;
1165
- /**
1166
- * A SIBLING transport on the same broker/connection, pinned to `namespace` (explicit — never
1167
- * re-scoped by a later {@link useNamespace}). Powers the tenant-worker bridge preset
1168
- * (`topology: { role: 'control-plane', tenant, tenantWorkers: 'bridge' }`): a tenant-scoped
1169
- * operator pairs its namespaced primary with `withNamespace('default')` — a bare-prefix sibling —
1170
- * so operator-convention tenant workers (`<group>@<tenant>` under the bare prefix) are
1171
- * discoverable and dispatchable. Optional — transports that don't partition simply omit it.
1172
- */
1173
- withNamespace?(namespace: string): Transport;
1174
1158
  /** Release the transport's resources (broker workers, queues, connections) for a clean shutdown.
1175
1159
  * Optional — an in-process transport has nothing to close. Called on `onApplicationShutdown`
1176
1160
  * after the engine drains, so a deploy hands off instead of leaving the broker to time out. */
@@ -3562,7 +3546,7 @@ declare function readSearchAttributes<S extends SearchAttributesSchema>(schema:
3562
3546
 
3563
3547
  /**
3564
3548
  * Compute the worker group a tenant's run dispatches to. Mirrors the transport's
3565
- * default-is-bare rule (see {@link TransportPool.useNamespace}'s `'default'` no-op): a
3549
+ * default-is-bare rule (unset/empty/`'default'` ⇒ bare): a
3566
3550
  * `tenant` of `undefined`, `''`, or `'default'` is the bare `baseGroup`, so a single-tenant
3567
3551
  * deployment (or the `'default'` tenant of a multi-tenant one) stays byte-identical to today.
3568
3552
  * Any other tenant suffixes the group as `<baseGroup>@<tenant>`, so an operator control plane
package/dist/index.js CHANGED
@@ -1113,17 +1113,6 @@ var TransportPool = class {
1113
1113
  }
1114
1114
  return void 0;
1115
1115
  }
1116
- /**
1117
- * Propagate the engine's `namespace` to every transport that partitions by it — so the same
1118
- * namespace that scopes the store also scopes each transport's queues/keys. A transport that
1119
- * doesn't partition (no `useNamespace`) is skipped. Idempotent; a transport given an explicit
1120
- * namespace at construction ignores this (see {@link Transport.useNamespace}).
1121
- */
1122
- useNamespace(namespace) {
1123
- for (const { transport } of this.transports) {
1124
- transport.useNamespace?.(namespace);
1125
- }
1126
- }
1127
1116
  /** Pinned `preferId` first, then the rest (failover order). */
1128
1117
  ordered(preferId) {
1129
1118
  if (!preferId) return this.transports;
@@ -1504,6 +1493,22 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
1504
1493
  runId,
1505
1494
  seq: current
1506
1495
  });
1496
+ const buffered = await store.takeBufferedSignal(`child:${id}`);
1497
+ if (buffered) {
1498
+ await store.removeSignalWaiter({
1499
+ token: `child:${id}`,
1500
+ runId,
1501
+ seq: current
1502
+ });
1503
+ await writeCheckpoint(instantCheckpoint({
1504
+ runId,
1505
+ seq: current,
1506
+ name: `signal:child:${id}`,
1507
+ kind: "signal",
1508
+ output: buffered.payload
1509
+ }));
1510
+ return unwrapCompletion(buffered.payload, `child "${id}"`);
1511
+ }
1507
1512
  if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority);
1508
1513
  if (!existing) {
1509
1514
  await writeCheckpoint(instantCheckpoint({
@@ -1945,9 +1950,6 @@ var WorkflowEngine = class {
1945
1950
  this.admission.onFreed?.((queue) => this.wakeQueueWaiters(queue));
1946
1951
  this.instanceId = deps.instanceId ?? globalThis.crypto.randomUUID();
1947
1952
  this.namespace = deps.namespace;
1948
- if (this.namespace !== void 0) {
1949
- this.pool.useNamespace(this.namespace);
1950
- }
1951
1953
  this.leaseMs = deps.leaseMs ?? 3e4;
1952
1954
  this.maxRecoveryAttempts = deps.maxRecoveryAttempts;
1953
1955
  this.remoteAdvanceSilenceMs = deps.remoteAdvanceSilenceMs;
@@ -2727,6 +2729,30 @@ var WorkflowEngine = class {
2727
2729
  async requeue(runId) {
2728
2730
  const run = await this.store.getRun(runId);
2729
2731
  if (!run) return null;
2732
+ if (run.status === "failed" || run.status === "dead") {
2733
+ const isFailureCompletion = /* @__PURE__ */ __name((v) => typeof v === "object" && v !== null && v.ok === false, "isFailureCompletion");
2734
+ for (const cp of await this.store.listCheckpoints(runId)) {
2735
+ if (cp.status === "failed") {
2736
+ await this.store.saveCheckpoint({
2737
+ ...cp,
2738
+ attempts: 0,
2739
+ wakeAt: this.clock(),
2740
+ ...cp.error ? {
2741
+ error: {
2742
+ ...cp.error,
2743
+ retryable: true
2744
+ }
2745
+ } : {}
2746
+ });
2747
+ } else if (cp.kind === "signal" && cp.name.startsWith("signal:child:") && cp.status === "completed" && isFailureCompletion(cp.output)) {
2748
+ await this.store.saveCheckpoint({
2749
+ ...cp,
2750
+ status: "running",
2751
+ output: void 0
2752
+ });
2753
+ }
2754
+ }
2755
+ }
2730
2756
  await this.store.releaseRunLock(runId);
2731
2757
  await this.store.updateRun(runId, {
2732
2758
  status: "pending",