@dudousxd/nestjs-durable-core 0.75.2 → 0.76.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.cjs CHANGED
@@ -4341,7 +4341,18 @@ var WorkflowEngine = class {
4341
4341
  createdAt: now,
4342
4342
  updatedAt: now
4343
4343
  };
4344
- await this.store.createRun(run);
4344
+ try {
4345
+ await this.store.createRun(run);
4346
+ } catch (err) {
4347
+ const winner = await this.store.getRun(runId).catch(() => null);
4348
+ if (!winner) throw err;
4349
+ return {
4350
+ runId,
4351
+ status: winner.status,
4352
+ output: winner.output,
4353
+ error: winner.error
4354
+ };
4355
+ }
4345
4356
  await this.runDispatcher.dispatch(runId);
4346
4357
  if (this.controlPlane) {
4347
4358
  void this.controlPlane.publishControl({
@@ -7254,10 +7265,12 @@ var WorkflowEngine = class {
7254
7265
  if (this.remoteRedispatchMs == null) throw new WorkflowSuspended();
7255
7266
  if (existing.wakeAt == null) {
7256
7267
  const wakeAt = this.clock() + this.remoteRedispatchMs;
7257
- await this.store.saveCheckpoint({
7268
+ if (!await this.savePendingCheckpoint({
7258
7269
  ...existing,
7259
7270
  wakeAt
7260
- });
7271
+ })) {
7272
+ return this.callRemote(runId, seq, step, input, queue, transport, void 0, admission, routing);
7273
+ }
7261
7274
  throw new WorkflowSuspended(wakeAt);
7262
7275
  }
7263
7276
  if (this.clock() < existing.wakeAt) throw new WorkflowSuspended(existing.wakeAt);
@@ -7270,7 +7283,7 @@ var WorkflowEngine = class {
7270
7283
  const reAttempt = existing.attempts + 1;
7271
7284
  const nextDeadline = this.clock() + this.remoteRedispatchMs;
7272
7285
  const reEnqueuedAt = /* @__PURE__ */ new Date();
7273
- await this.store.saveCheckpoint({
7286
+ const claimed = await this.savePendingCheckpoint({
7274
7287
  ...existing,
7275
7288
  attempts: reAttempt,
7276
7289
  wakeAt: nextDeadline,
@@ -7284,6 +7297,9 @@ var WorkflowEngine = class {
7284
7297
  lostStepEvent(this.clock(), reAttempt, "redispatched")
7285
7298
  ]
7286
7299
  });
7300
+ if (!claimed) {
7301
+ return this.callRemote(runId, seq, step, input, queue, transport, void 0, admission, routing);
7302
+ }
7287
7303
  await this.dispatchRemoteTask({
7288
7304
  runId,
7289
7305
  seq,
@@ -7374,6 +7390,12 @@ var WorkflowEngine = class {
7374
7390
  this.awaitedRemoteSteps.get(runId)?.add(seq);
7375
7391
  throw new WorkflowSuspended();
7376
7392
  }
7393
+ /** {@link StateStore.saveCheckpointIfPending}, or a plain save on a store without it. */
7394
+ async savePendingCheckpoint(checkpoint) {
7395
+ if (this.store.saveCheckpointIfPending) return this.store.saveCheckpointIfPending(checkpoint);
7396
+ await this.store.saveCheckpoint(checkpoint);
7397
+ return true;
7398
+ }
7377
7399
  /** Enqueue a remote step task to its worker group via the transport pool. Shared by the initial
7378
7400
  * dispatch, the opt-in self-heal re-dispatch (see `remoteRedispatchMs`), and the explicit
7379
7401
  * {@link redispatchPending}. Carries the current trace/context so a re-dispatch is traceable. */
@@ -7404,7 +7426,7 @@ var WorkflowEngine = class {
7404
7426
  if (run && (run.status === "cancelled" || run.status === "completed")) return;
7405
7427
  const finishedAt = /* @__PURE__ */ new Date();
7406
7428
  const startedAt = result.startedAt ? new Date(result.startedAt) : cp.startedAt;
7407
- await this.store.saveCheckpoint({
7429
+ const claimed = await this.savePendingCheckpoint({
7408
7430
  ...cp,
7409
7431
  status: result.status,
7410
7432
  output: result.status === "completed" ? result.output : cp.output,
@@ -7413,6 +7435,7 @@ var WorkflowEngine = class {
7413
7435
  startedAt,
7414
7436
  finishedAt
7415
7437
  });
7438
+ if (!claimed) return;
7416
7439
  this.emit({
7417
7440
  type: result.status === "completed" ? "step.completed" : "step.failed",
7418
7441
  runId: result.runId,
@@ -7805,6 +7828,9 @@ var CodecStateStore = class {
7805
7828
  /** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
7806
7829
  * engine's per-run fallback still kicks in through the wrapper. */
7807
7830
  deleteRuns;
7831
+ /** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
7832
+ * plain-save fallback still kicks in through the wrapper. */
7833
+ saveCheckpointIfPending;
7808
7834
  /** Forwarded verbatim — retention selects by status/updatedAt/scope, never by payload. Bound only
7809
7835
  * when the inner store prunes, so the retention poller still sees (and warns about) its absence. */
7810
7836
  pruneTerminalRuns;
@@ -7832,6 +7858,8 @@ var CodecStateStore = class {
7832
7858
  if (inner.tryAdmitSingleton) this.tryAdmitSingleton = inner.tryAdmitSingleton.bind(inner);
7833
7859
  const deleteRuns = inner.deleteRuns;
7834
7860
  if (deleteRuns) this.deleteRuns = (ids) => deleteRuns.call(inner, ids);
7861
+ const saveIfPending = inner.saveCheckpointIfPending;
7862
+ if (saveIfPending) this.saveCheckpointIfPending = (cp) => saveIfPending.call(inner, this.encCp(cp));
7835
7863
  const prune = inner.pruneTerminalRuns;
7836
7864
  if (prune) this.pruneTerminalRuns = (policy, now, limit) => prune.call(inner, policy, now, limit);
7837
7865
  const count = inner.countRuns;
@@ -8395,6 +8423,14 @@ var InMemoryStateStore = class {
8395
8423
  ...checkpoint
8396
8424
  });
8397
8425
  }
8426
+ async saveCheckpointIfPending(checkpoint) {
8427
+ const key = this.key(checkpoint.runId, checkpoint.seq);
8428
+ if (this.checkpoints.get(key)?.status !== "pending") return false;
8429
+ this.checkpoints.set(key, {
8430
+ ...checkpoint
8431
+ });
8432
+ return true;
8433
+ }
8398
8434
  async listIncompleteRuns(namespace) {
8399
8435
  return [
8400
8436
  ...this.runs.values()