@smithers-orchestrator/scheduler 0.21.0 → 0.23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smithers-orchestrator/scheduler",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "Pure decision engine: session, scheduler, and task state management for Smithers workflows",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -176,8 +176,8 @@
176
176
  ],
177
177
  "dependencies": {
178
178
  "effect": "^3.21.1",
179
- "@smithers-orchestrator/errors": "0.21.0",
180
- "@smithers-orchestrator/graph": "0.21.0"
179
+ "@smithers-orchestrator/errors": "0.23.0",
180
+ "@smithers-orchestrator/graph": "0.23.0"
181
181
  },
182
182
  "devDependencies": {
183
183
  "@types/bun": "latest",
@@ -1,4 +1,4 @@
1
- export type CachePolicy<Ctx = any> = {
1
+ export type CachePolicy<Ctx = unknown> = {
2
2
  by?: (ctx: Ctx) => unknown;
3
3
  version?: string;
4
4
  key?: string;
@@ -286,6 +286,8 @@ export function makeWorkflowSession(options = {}) {
286
286
  state.states.delete(key);
287
287
  }
288
288
  state.retryWait.delete(key);
289
+ state.approvals.delete(key);
290
+ state.retryCounts.delete(key);
289
291
  }
290
292
  }
291
293
  for (const ralph of ralphs) {
@@ -38,9 +38,7 @@ function isTraversalTerminal(state, descriptor) {
38
38
  * @returns {boolean}
39
39
  */
40
40
  function dependenciesSatisfied(descriptor, states, descriptors) {
41
- if (!descriptor.dependsOn || descriptor.dependsOn.length === 0)
42
- return true;
43
- for (const dependencyId of descriptor.dependsOn) {
41
+ for (const dependencyId of descriptor.dependsOn ?? []) {
44
42
  const dependency = descriptors.get(dependencyId);
45
43
  if (!dependency)
46
44
  return false;
@@ -49,8 +47,44 @@ function dependenciesSatisfied(descriptor, states, descriptors) {
49
47
  return false;
50
48
  }
51
49
  }
50
+ // A forked task waits until its source task has a completed (terminal)
51
+ // execution. The source is matched by logical id so a source inside a loop
52
+ // is satisfied by whichever iteration has completed; the executor then
53
+ // forks the latest completed snapshot for that id.
54
+ if (descriptor.forkSource && !forkSourceTerminal(descriptor.forkSource, states, descriptors)) {
55
+ return false;
56
+ }
52
57
  return true;
53
58
  }
59
+ /**
60
+ * Strip the loop-scope suffix (`@@ralph=0,...`) from a node id to recover the
61
+ * logical task id authored in JSX.
62
+ * @param {string} nodeId
63
+ * @returns {string}
64
+ */
65
+ function logicalNodeId(nodeId) {
66
+ const atIdx = nodeId.indexOf("@@");
67
+ return atIdx === -1 ? nodeId : nodeId.slice(0, atIdx);
68
+ }
69
+ /**
70
+ * Whether any execution of the fork source task (matched by logical id) has
71
+ * reached a terminal state.
72
+ * @param {string} forkSource
73
+ * @param {TaskStateMap} states
74
+ * @param {Map<string, TaskDescriptor>} descriptors
75
+ * @returns {boolean}
76
+ */
77
+ function forkSourceTerminal(forkSource, states, descriptors) {
78
+ for (const descriptor of descriptors.values()) {
79
+ if (logicalNodeId(descriptor.nodeId) !== forkSource)
80
+ continue;
81
+ const state = states.get(buildStateKey(descriptor.nodeId, descriptor.iteration));
82
+ if (state && isTerminal(state, descriptor)) {
83
+ return true;
84
+ }
85
+ }
86
+ return false;
87
+ }
54
88
  /**
55
89
  * @param {PlanNode | null} plan
56
90
  * @param {TaskStateMap} states