@dudousxd/nestjs-durable-core 0.32.0 → 0.33.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
@@ -29,6 +29,7 @@ __export(index_exports, {
29
29
  Entities: () => Entities,
30
30
  EventAccumulators: () => EventAccumulators,
31
31
  FatalError: () => FatalError,
32
+ GatherError: () => GatherError,
32
33
  InMemoryAdmissionBackend: () => InMemoryAdmissionBackend,
33
34
  InMemoryStateStore: () => InMemoryStateStore,
34
35
  InMemoryTransport: () => InMemoryTransport,
@@ -37,6 +38,7 @@ __export(index_exports, {
37
38
  RemoteStepError: () => RemoteStepError,
38
39
  RemoteStepTimeout: () => RemoteStepTimeout,
39
40
  RemoteWorkflowExecutor: () => RemoteWorkflowExecutor,
41
+ RemoteWorkflowTimeout: () => RemoteWorkflowTimeout,
40
42
  STATE_STORE: () => STATE_STORE,
41
43
  STATE_STORE_CANONICAL: () => STATE_STORE_CANONICAL,
42
44
  SignalTimeoutError: () => SignalTimeoutError,
@@ -51,6 +53,7 @@ __export(index_exports, {
51
53
  attributeOperand: () => attributeOperand,
52
54
  breakpointToken: () => breakpointToken,
53
55
  collectMetrics: () => collectMetrics,
56
+ createStepLogger: () => createStepLogger,
54
57
  eventMatchOf: () => eventMatchOf,
55
58
  eventMatches: () => eventMatches,
56
59
  eventPrefix: () => eventPrefix,
@@ -453,6 +456,7 @@ function stepCheckpoint(p) {
453
456
  attempts: p.attempts,
454
457
  workerGroup: p.workerGroup,
455
458
  wakeAt: p.wakeAt,
459
+ parallelGroup: p.parallelGroup,
456
460
  enqueuedAt: p.enqueuedAt,
457
461
  startedAt: p.startedAt,
458
462
  finishedAt: p.finishedAt
@@ -470,6 +474,7 @@ function instantCheckpoint(p) {
470
474
  status: p.status ?? "completed",
471
475
  output: p.output,
472
476
  wakeAt: p.wakeAt,
477
+ parallelGroup: p.parallelGroup,
473
478
  attempts: 1,
474
479
  enqueuedAt: at,
475
480
  startedAt: at,
@@ -531,6 +536,19 @@ var RemoteStepTimeout = class extends Error {
531
536
  this.timeoutMs = timeoutMs;
532
537
  }
533
538
  };
539
+ var RemoteWorkflowTimeout = class extends Error {
540
+ static {
541
+ __name(this, "RemoteWorkflowTimeout");
542
+ }
543
+ taskId;
544
+ timeoutMs;
545
+ constructor(taskId, timeoutMs) {
546
+ super(`remote workflow task ${taskId} produced no decision within ${timeoutMs}ms \u2014 presumed dropped; re-driving via recovery`);
547
+ this.name = "RemoteWorkflowTimeout";
548
+ this.taskId = taskId;
549
+ this.timeoutMs = timeoutMs;
550
+ }
551
+ };
534
552
  var NonDeterminismError = class extends Error {
535
553
  static {
536
554
  __name(this, "NonDeterminismError");
@@ -544,6 +562,19 @@ var NonDeterminismError = class extends Error {
544
562
  this.seq = seq;
545
563
  }
546
564
  };
565
+ var GatherError = class extends Error {
566
+ static {
567
+ __name(this, "GatherError");
568
+ }
569
+ failures;
570
+ constructor(failures, total) {
571
+ const ids = failures.map((f) => f.id).join(", ");
572
+ const denom = total ?? failures.length;
573
+ super(`ctx.all: ${failures.length} of ${denom} child(ren) failed: ${ids}`);
574
+ this.name = "GatherError";
575
+ this.failures = failures;
576
+ }
577
+ };
547
578
  var WorkflowSuspended = class extends Error {
548
579
  static {
549
580
  __name(this, "WorkflowSuspended");
@@ -1213,6 +1244,72 @@ function createWorkflowCtx(host, runId, compensations, workflow = "") {
1213
1244
  }
1214
1245
  throw new WorkflowSuspended();
1215
1246
  }, "child");
1247
+ const all = /* @__PURE__ */ __name(async (workflow2, inputs, opts) => {
1248
+ if (inputs.length === 0) return [];
1249
+ const mode = opts?.mode ?? "waitAll";
1250
+ const name = workflowName(workflow2);
1251
+ const positions = inputs.map(() => pos.next());
1252
+ const group = `all:${positions[0]}`;
1253
+ const id = /* @__PURE__ */ __name((i) => `${runId}.all.${positions[0]}.${i}`, "id");
1254
+ const existing = await Promise.all(positions.map((seq) => readCheckpoint(seq)));
1255
+ if (mode === "failFast") {
1256
+ for (let i = 0; i < inputs.length; i += 1) {
1257
+ const cp = existing[i];
1258
+ const c = cp?.status === "completed" ? cp.output : null;
1259
+ if (c && c.ok === false) {
1260
+ throw new GatherError([
1261
+ {
1262
+ index: i,
1263
+ id: id(i),
1264
+ error: c.error ?? "unknown"
1265
+ }
1266
+ ], inputs.length);
1267
+ }
1268
+ }
1269
+ }
1270
+ let pending = false;
1271
+ for (let i = 0; i < inputs.length; i += 1) {
1272
+ const cp = existing[i];
1273
+ if (cp?.status === "completed") continue;
1274
+ pending = true;
1275
+ const seq = positions[i];
1276
+ const childId = id(i);
1277
+ await store.putSignalWaiter({
1278
+ token: `child:${childId}`,
1279
+ runId,
1280
+ seq
1281
+ });
1282
+ if (!await store.getRun(childId)) host.startChild(name, inputs[i], childId);
1283
+ if (!cp) {
1284
+ await writeCheckpoint(instantCheckpoint({
1285
+ runId,
1286
+ seq,
1287
+ name: `signal:child:${childId}`,
1288
+ kind: "signal",
1289
+ status: "running",
1290
+ parallelGroup: group
1291
+ }));
1292
+ }
1293
+ }
1294
+ if (pending) throw new WorkflowSuspended();
1295
+ const outputs = [];
1296
+ const failures = [];
1297
+ for (let i = 0; i < inputs.length; i += 1) {
1298
+ const c = existing[i]?.output;
1299
+ if (c && typeof c === "object" && "ok" in c && c.ok === false) {
1300
+ failures.push({
1301
+ index: i,
1302
+ id: id(i),
1303
+ error: c.error ?? "unknown"
1304
+ });
1305
+ outputs.push(void 0);
1306
+ } else {
1307
+ outputs.push(c?.value);
1308
+ }
1309
+ }
1310
+ if (failures.length > 0) throw new GatherError(failures, inputs.length);
1311
+ return outputs;
1312
+ }, "all");
1216
1313
  const startChild = /* @__PURE__ */ __name(async (workflow2, input, options) => {
1217
1314
  const { childId, priority } = normalizeChildOptions(options);
1218
1315
  const current = pos.next();
@@ -1347,6 +1444,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "") {
1347
1444
  waitForEvent,
1348
1445
  task,
1349
1446
  child,
1447
+ all,
1350
1448
  startChild,
1351
1449
  breakpoint,
1352
1450
  webhook,
@@ -2336,7 +2434,8 @@ var WorkflowEngine = class {
2336
2434
  attempts: 1,
2337
2435
  enqueuedAt: startedAt,
2338
2436
  startedAt,
2339
- finishedAt: startedAt
2437
+ finishedAt: startedAt,
2438
+ parallelGroup: event.parallelGroup
2340
2439
  }));
2341
2440
  this.emit({
2342
2441
  type: "step.started",
@@ -2360,7 +2459,8 @@ var WorkflowEngine = class {
2360
2459
  attempts: 1,
2361
2460
  enqueuedAt: startedAt,
2362
2461
  startedAt,
2363
- finishedAt: event.finishedAt != null ? new Date(event.finishedAt) : /* @__PURE__ */ new Date()
2462
+ finishedAt: event.finishedAt != null ? new Date(event.finishedAt) : /* @__PURE__ */ new Date(),
2463
+ parallelGroup: event.parallelGroup
2364
2464
  }));
2365
2465
  this.emit({
2366
2466
  type: failed ? "step.failed" : "step.completed",
@@ -2597,6 +2697,13 @@ var WorkflowEngine = class {
2597
2697
  try {
2598
2698
  decision = await remote.executor.advance(run, history);
2599
2699
  } catch (err) {
2700
+ if (err instanceof RemoteWorkflowTimeout) {
2701
+ await this.store.releaseRunLock(run.id);
2702
+ return {
2703
+ runId: run.id,
2704
+ status: "running"
2705
+ };
2706
+ }
2600
2707
  const error = {
2601
2708
  message: err instanceof Error ? err.message : String(err),
2602
2709
  stack: err instanceof Error ? err.stack : void 0
@@ -2716,7 +2823,11 @@ var WorkflowEngine = class {
2716
2823
  attempts: 1,
2717
2824
  enqueuedAt: startedAt,
2718
2825
  startedAt,
2719
- finishedAt
2826
+ finishedAt,
2827
+ // Carry the worker's `parallelGroup` (a Python `ctx.gather` tags every step in the fan with
2828
+ // the same group) onto the checkpoint, so the dashboard can render the steps as one parallel
2829
+ // group instead of a sequential list. Additive: undefined for ordinary sequential steps.
2830
+ parallelGroup: cmd.parallelGroup
2720
2831
  }));
2721
2832
  this.emit({
2722
2833
  type: cmd.error ? "step.failed" : "step.completed",
@@ -3351,11 +3462,12 @@ var RemoteWorkflowExecutor = class {
3351
3462
  };
3352
3463
  const decision = new Promise((resolve, reject) => {
3353
3464
  this.pending.set(taskId, resolve);
3354
- if (this.opts.timeoutMs) {
3465
+ const { timeoutMs } = this.opts;
3466
+ if (timeoutMs) {
3355
3467
  const timer = setTimeout(() => {
3356
3468
  this.pending.delete(taskId);
3357
- reject(new Error(`workflow task ${taskId} timed out after ${this.opts.timeoutMs}ms`));
3358
- }, this.opts.timeoutMs);
3469
+ reject(new RemoteWorkflowTimeout(taskId, timeoutMs));
3470
+ }, timeoutMs);
3359
3471
  timer.unref?.();
3360
3472
  }
3361
3473
  });
@@ -4083,6 +4195,7 @@ var InMemoryTransport = class {
4083
4195
  Entities,
4084
4196
  EventAccumulators,
4085
4197
  FatalError,
4198
+ GatherError,
4086
4199
  InMemoryAdmissionBackend,
4087
4200
  InMemoryStateStore,
4088
4201
  InMemoryTransport,
@@ -4091,6 +4204,7 @@ var InMemoryTransport = class {
4091
4204
  RemoteStepError,
4092
4205
  RemoteStepTimeout,
4093
4206
  RemoteWorkflowExecutor,
4207
+ RemoteWorkflowTimeout,
4094
4208
  STATE_STORE,
4095
4209
  STATE_STORE_CANONICAL,
4096
4210
  SignalTimeoutError,
@@ -4105,6 +4219,7 @@ var InMemoryTransport = class {
4105
4219
  attributeOperand,
4106
4220
  breakpointToken,
4107
4221
  collectMetrics,
4222
+ createStepLogger,
4108
4223
  eventMatchOf,
4109
4224
  eventMatches,
4110
4225
  eventPrefix,