@adonis-agora/durable 0.55.1 → 0.56.1

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/providers/dashboard_provider.d.ts +7 -2
  3. package/dist/providers/dashboard_provider.d.ts.map +1 -1
  4. package/dist/providers/dashboard_provider.js +34 -8
  5. package/dist/providers/dashboard_provider.js.map +1 -1
  6. package/dist/src/dashboard/define_config.d.ts +37 -5
  7. package/dist/src/dashboard/define_config.d.ts.map +1 -1
  8. package/dist/src/dashboard/define_config.js +19 -0
  9. package/dist/src/dashboard/define_config.js.map +1 -1
  10. package/dist/src/dashboard/index.d.ts +3 -3
  11. package/dist/src/dashboard/index.d.ts.map +1 -1
  12. package/dist/src/dashboard/index.js +2 -2
  13. package/dist/src/dashboard/index.js.map +1 -1
  14. package/dist/src/engine.d.ts +13 -5
  15. package/dist/src/engine.d.ts.map +1 -1
  16. package/dist/src/engine.js +52 -24
  17. package/dist/src/engine.js.map +1 -1
  18. package/dist/src/index.d.ts +1 -1
  19. package/dist/src/index.js +1 -1
  20. package/dist/src/transports/adaptive-concurrency.d.ts.map +1 -1
  21. package/dist/src/transports/adaptive-concurrency.js +7 -1
  22. package/dist/src/transports/adaptive-concurrency.js.map +1 -1
  23. package/dist/src/transports/bullmq/bullmq-transport.d.ts.map +1 -1
  24. package/dist/src/transports/bullmq/bullmq-transport.js +91 -2
  25. package/dist/src/transports/bullmq/bullmq-transport.js.map +1 -1
  26. package/dist/src/transports/bullmq/deps.d.ts +5 -0
  27. package/dist/src/transports/bullmq/deps.d.ts.map +1 -1
  28. package/dist/src/transports/bullmq/deps.js.map +1 -1
  29. package/dist/src/transports/bullmq/naming.d.ts +6 -0
  30. package/dist/src/transports/bullmq/naming.d.ts.map +1 -1
  31. package/dist/src/transports/bullmq/naming.js +8 -0
  32. package/dist/src/transports/bullmq/naming.js.map +1 -1
  33. package/dist/stubs/config/durable_dashboard.stub +3 -1
  34. package/package.json +1 -1
  35. package/skills/durable-transports-stores/SKILL.md +2 -2
@@ -116,6 +116,12 @@ const isTerminalRun = (status) => TERMINAL_RUN_STATUSES.includes(status);
116
116
  const COMPENSATION_SEQ_BASE = -2;
117
117
  /** How many checkpoint writes / dispatches a step fan sends at once. */
118
118
  const STEP_FAN_CHUNK = 200;
119
+ /**
120
+ * Most steps of a fan one write-then-dispatch round of {@link WorkflowEngine.sendStepFan} carries.
121
+ * Workers start on a round's steps while the next round's checkpoints are written, instead of
122
+ * waiting for every checkpoint of a wide fan to commit.
123
+ */
124
+ const STEP_FAN_SEND_ROUND = 2000;
119
125
  /** The default {@link WorkflowEngineDeps.timerBatchSize}. */
120
126
  const DEFAULT_TIMER_BATCH = 500;
121
127
  /** {@link WorkflowEngine.sweepBufferedSignals}: rows read per page. */
@@ -6441,11 +6447,27 @@ export class WorkflowEngine {
6441
6447
  return true;
6442
6448
  return cp.wakeAt != null && this.clock() < cp.wakeAt;
6443
6449
  }
6450
+ /** Write a round of a step fan's checkpoints: one call where the store batches, else chunked. */
6451
+ async saveFanCheckpoints(checkpoints) {
6452
+ if (this.store.saveCheckpoints) {
6453
+ await this.store.saveCheckpoints(checkpoints);
6454
+ return;
6455
+ }
6456
+ for (let at = 0; at < checkpoints.length; at += STEP_FAN_CHUNK) {
6457
+ await Promise.all(checkpoints.slice(at, at + STEP_FAN_CHUNK).map((cp) => this.store.saveCheckpoint(cp)));
6458
+ }
6459
+ }
6444
6460
  /**
6445
- * Write the `pending` checkpoints of a step fan's new steps, then dispatch them: one
6446
- * {@link StateStore.saveCheckpoints} call and one {@link TransportPool.dispatchMany} for the batch,
6447
- * where the store and transport have them. With the lost-dispatch self-heal on, each step is
6448
- * written with its lease already stamped, and the lease is returned for the run to park on.
6461
+ * Write the `pending` checkpoints of a step fan's new steps and dispatch them, in rounds of
6462
+ * {@link STEP_FAN_SEND_ROUND}: a round's steps are dispatched once its checkpoints commit, while the
6463
+ * next round's are written. One {@link StateStore.saveCheckpoints} call and one
6464
+ * {@link TransportPool.dispatchMany} per round, where the store and transport have them. With the
6465
+ * lost-dispatch self-heal on, each step is written with its lease already stamped, and the lease is
6466
+ * returned for the run to park on.
6467
+ *
6468
+ * No result can wake the run before every round is written: the run is `running` under this
6469
+ * turn's lease until the turn suspends. A send cut short leaves the unwritten steps without a
6470
+ * checkpoint, and the replay sends them once the written ones settle.
6449
6471
  */
6450
6472
  async sendStepFan(runId, positions, step, inputs, batch, group, opts, runNamespace) {
6451
6473
  const token = stepGroup(step, runNamespace);
@@ -6477,28 +6499,34 @@ export class WorkflowEngine {
6477
6499
  ...(lease !== undefined ? { wakeAt: lease } : {}),
6478
6500
  };
6479
6501
  });
6480
- if (this.store.saveCheckpoints) {
6481
- await this.store.saveCheckpoints(checkpoints);
6482
- }
6483
- else {
6484
- for (let at = 0; at < checkpoints.length; at += STEP_FAN_CHUNK) {
6485
- await Promise.all(checkpoints.slice(at, at + STEP_FAN_CHUNK).map((cp) => this.store.saveCheckpoint(cp)));
6486
- }
6487
- }
6488
6502
  const traceparent = this.traceparent?.();
6489
6503
  const context = this.context?.();
6490
- await this.pool.dispatchMany(checkpoints.map((cp) => ({
6491
- runId,
6492
- seq: cp.seq,
6493
- name: step.name,
6494
- stepId: cp.stepId,
6495
- group: token,
6496
- input: cp.input,
6497
- traceparent,
6498
- context,
6499
- priority: opts.admission?.priority,
6500
- attempt: 1,
6501
- })), opts.transport);
6504
+ const dispatches = [];
6505
+ try {
6506
+ for (let from = 0; from < checkpoints.length; from += STEP_FAN_SEND_ROUND) {
6507
+ const round = checkpoints.slice(from, from + STEP_FAN_SEND_ROUND);
6508
+ await this.saveFanCheckpoints(round);
6509
+ const dispatch = this.pool.dispatchMany(round.map((cp) => ({
6510
+ runId,
6511
+ seq: cp.seq,
6512
+ name: step.name,
6513
+ stepId: cp.stepId,
6514
+ group: token,
6515
+ input: cp.input,
6516
+ traceparent,
6517
+ context,
6518
+ priority: opts.admission?.priority,
6519
+ attempt: 1,
6520
+ })), opts.transport);
6521
+ // Awaited below; a rejection is not left unhandled while the next round is written.
6522
+ dispatch.catch(() => { });
6523
+ dispatches.push(dispatch);
6524
+ }
6525
+ }
6526
+ finally {
6527
+ await Promise.allSettled(dispatches);
6528
+ }
6529
+ await Promise.all(dispatches);
6502
6530
  for (const cp of checkpoints) {
6503
6531
  this.emit({ type: 'step.started', runId, seq: cp.seq, name: step.name, kind: 'remote' });
6504
6532
  }