@calmo/task-runner 3.8.2 → 3.8.3
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/CHANGELOG.md +5 -0
- package/coverage/coverage-final.json +4 -3
- package/coverage/index.html +9 -9
- package/coverage/lcov-report/index.html +9 -9
- package/coverage/lcov-report/src/EventBus.ts.html +4 -4
- package/coverage/lcov-report/src/ExecutionConstants.ts.html +121 -0
- package/coverage/lcov-report/src/TaskGraphValidationError.ts.html +1 -1
- package/coverage/lcov-report/src/TaskGraphValidator.ts.html +1 -1
- package/coverage/lcov-report/src/TaskRunner.ts.html +1 -1
- package/coverage/lcov-report/src/TaskRunnerBuilder.ts.html +1 -1
- package/coverage/lcov-report/src/TaskRunnerExecutionConfig.ts.html +1 -1
- package/coverage/lcov-report/src/TaskStateManager.ts.html +34 -34
- package/coverage/lcov-report/src/WorkflowExecutor.ts.html +151 -97
- package/coverage/lcov-report/src/contracts/ErrorTypes.ts.html +1 -1
- package/coverage/lcov-report/src/contracts/RunnerEvents.ts.html +1 -1
- package/coverage/lcov-report/src/contracts/index.html +1 -1
- package/coverage/lcov-report/src/index.html +24 -9
- package/coverage/lcov-report/src/strategies/DryRunExecutionStrategy.ts.html +1 -1
- package/coverage/lcov-report/src/strategies/RetryingExecutionStrategy.ts.html +1 -1
- package/coverage/lcov-report/src/strategies/StandardExecutionStrategy.ts.html +1 -1
- package/coverage/lcov-report/src/strategies/index.html +1 -1
- package/coverage/lcov.info +184 -171
- package/coverage/src/EventBus.ts.html +4 -4
- package/coverage/src/ExecutionConstants.ts.html +121 -0
- package/coverage/src/TaskGraphValidationError.ts.html +1 -1
- package/coverage/src/TaskGraphValidator.ts.html +1 -1
- package/coverage/src/TaskRunner.ts.html +1 -1
- package/coverage/src/TaskRunnerBuilder.ts.html +1 -1
- package/coverage/src/TaskRunnerExecutionConfig.ts.html +1 -1
- package/coverage/src/TaskStateManager.ts.html +34 -34
- package/coverage/src/WorkflowExecutor.ts.html +151 -97
- package/coverage/src/contracts/ErrorTypes.ts.html +1 -1
- package/coverage/src/contracts/RunnerEvents.ts.html +1 -1
- package/coverage/src/contracts/index.html +1 -1
- package/coverage/src/index.html +24 -9
- package/coverage/src/strategies/DryRunExecutionStrategy.ts.html +1 -1
- package/coverage/src/strategies/RetryingExecutionStrategy.ts.html +1 -1
- package/coverage/src/strategies/StandardExecutionStrategy.ts.html +1 -1
- package/coverage/src/strategies/index.html +1 -1
- package/dist/ExecutionConstants.d.ts +12 -0
- package/dist/ExecutionConstants.js +13 -0
- package/dist/ExecutionConstants.js.map +1 -0
- package/dist/WorkflowExecutor.d.ts +4 -0
- package/dist/WorkflowExecutor.js +62 -49
- package/dist/WorkflowExecutor.js.map +1 -1
- package/package.json +1 -1
- package/src/ExecutionConstants.ts +12 -0
- package/src/WorkflowExecutor.ts +69 -51
- package/test-report.xml +146 -140
package/coverage/src/index.html
CHANGED
|
@@ -25,28 +25,28 @@
|
|
|
25
25
|
<div class='fl pad1y space-right2'>
|
|
26
26
|
<span class="strong">100% </span>
|
|
27
27
|
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>
|
|
28
|
+
<span class='fraction'>261/261</span>
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
<div class='fl pad1y space-right2'>
|
|
33
33
|
<span class="strong">100% </span>
|
|
34
34
|
<span class="quiet">Branches</span>
|
|
35
|
-
<span class='fraction'>
|
|
35
|
+
<span class='fraction'>99/99</span>
|
|
36
36
|
</div>
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
<div class='fl pad1y space-right2'>
|
|
40
40
|
<span class="strong">100% </span>
|
|
41
41
|
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>
|
|
42
|
+
<span class='fraction'>50/50</span>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
<div class='fl pad1y space-right2'>
|
|
47
47
|
<span class="strong">100% </span>
|
|
48
48
|
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>
|
|
49
|
+
<span class='fraction'>258/258</span>
|
|
50
50
|
</div>
|
|
51
51
|
|
|
52
52
|
|
|
@@ -93,6 +93,21 @@
|
|
|
93
93
|
<td data-value="17" class="abs high">17/17</td>
|
|
94
94
|
</tr>
|
|
95
95
|
|
|
96
|
+
<tr>
|
|
97
|
+
<td class="file high" data-value="ExecutionConstants.ts"><a href="ExecutionConstants.ts.html">ExecutionConstants.ts</a></td>
|
|
98
|
+
<td data-value="100" class="pic high">
|
|
99
|
+
<div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
|
|
100
|
+
</td>
|
|
101
|
+
<td data-value="100" class="pct high">100%</td>
|
|
102
|
+
<td data-value="1" class="abs high">1/1</td>
|
|
103
|
+
<td data-value="100" class="pct high">100%</td>
|
|
104
|
+
<td data-value="0" class="abs high">0/0</td>
|
|
105
|
+
<td data-value="100" class="pct high">100%</td>
|
|
106
|
+
<td data-value="0" class="abs high">0/0</td>
|
|
107
|
+
<td data-value="100" class="pct high">100%</td>
|
|
108
|
+
<td data-value="1" class="abs high">1/1</td>
|
|
109
|
+
</tr>
|
|
110
|
+
|
|
96
111
|
<tr>
|
|
97
112
|
<td class="file high" data-value="TaskGraphValidationError.ts"><a href="TaskGraphValidationError.ts.html">TaskGraphValidationError.ts</a></td>
|
|
98
113
|
<td data-value="100" class="pic high">
|
|
@@ -189,13 +204,13 @@
|
|
|
189
204
|
<div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
|
|
190
205
|
</td>
|
|
191
206
|
<td data-value="100" class="pct high">100%</td>
|
|
192
|
-
<td data-value="
|
|
207
|
+
<td data-value="69" class="abs high">69/69</td>
|
|
193
208
|
<td data-value="100" class="pct high">100%</td>
|
|
194
|
-
<td data-value="
|
|
209
|
+
<td data-value="37" class="abs high">37/37</td>
|
|
195
210
|
<td data-value="100" class="pct high">100%</td>
|
|
196
|
-
<td data-value="
|
|
211
|
+
<td data-value="7" class="abs high">7/7</td>
|
|
197
212
|
<td data-value="100" class="pct high">100%</td>
|
|
198
|
-
<td data-value="
|
|
213
|
+
<td data-value="68" class="abs high">68/68</td>
|
|
199
214
|
</tr>
|
|
200
215
|
|
|
201
216
|
</tbody>
|
|
@@ -206,7 +221,7 @@
|
|
|
206
221
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
207
222
|
Code coverage generated by
|
|
208
223
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
209
|
-
at 2026-01-21T01:
|
|
224
|
+
at 2026-01-21T01:20:30.153Z
|
|
210
225
|
</div>
|
|
211
226
|
<script src="../prettify.js"></script>
|
|
212
227
|
<script>
|
|
@@ -163,7 +163,7 @@ export class DryRunExecutionStrategy<
|
|
|
163
163
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
164
164
|
Code coverage generated by
|
|
165
165
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
166
|
-
at 2026-01-21T01:
|
|
166
|
+
at 2026-01-21T01:20:30.153Z
|
|
167
167
|
</div>
|
|
168
168
|
<script src="../../prettify.js"></script>
|
|
169
169
|
<script>
|
|
@@ -358,7 +358,7 @@ export class RetryingExecutionStrategy<
|
|
|
358
358
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
359
359
|
Code coverage generated by
|
|
360
360
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
361
|
-
at 2026-01-21T01:
|
|
361
|
+
at 2026-01-21T01:20:30.153Z
|
|
362
362
|
</div>
|
|
363
363
|
<script src="../../prettify.js"></script>
|
|
364
364
|
<script>
|
|
@@ -175,7 +175,7 @@ export class StandardExecutionStrategy<
|
|
|
175
175
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
176
176
|
Code coverage generated by
|
|
177
177
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
178
|
-
at 2026-01-21T01:
|
|
178
|
+
at 2026-01-21T01:20:30.153Z
|
|
179
179
|
</div>
|
|
180
180
|
<script src="../../prettify.js"></script>
|
|
181
181
|
<script>
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
132
132
|
Code coverage generated by
|
|
133
133
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
134
|
-
at 2026-01-21T01:
|
|
134
|
+
at 2026-01-21T01:20:30.153Z
|
|
135
135
|
</div>
|
|
136
136
|
<script src="../../prettify.js"></script>
|
|
137
137
|
<script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used in the execution engine.
|
|
3
|
+
*/
|
|
4
|
+
export declare const ExecutionConstants: {
|
|
5
|
+
CANCELLED_BEFORE_START: string;
|
|
6
|
+
TASK_CANCELLED_BEFORE_START: string;
|
|
7
|
+
CANCELLED_DURING_CONDITION: string;
|
|
8
|
+
CONDITION_EVALUATION_FAILED: string;
|
|
9
|
+
SKIPPED_BY_CONDITION: string;
|
|
10
|
+
EXECUTION_STRATEGY_FAILED: string;
|
|
11
|
+
WORKFLOW_CANCELLED: string;
|
|
12
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used in the execution engine.
|
|
3
|
+
*/
|
|
4
|
+
export const ExecutionConstants = {
|
|
5
|
+
CANCELLED_BEFORE_START: "Workflow cancelled before execution started.",
|
|
6
|
+
TASK_CANCELLED_BEFORE_START: "Cancelled before execution started.",
|
|
7
|
+
CANCELLED_DURING_CONDITION: "Cancelled during condition evaluation.",
|
|
8
|
+
CONDITION_EVALUATION_FAILED: "Condition evaluation failed",
|
|
9
|
+
SKIPPED_BY_CONDITION: "Skipped by condition evaluation.",
|
|
10
|
+
EXECUTION_STRATEGY_FAILED: "Execution strategy failed.",
|
|
11
|
+
WORKFLOW_CANCELLED: "Workflow cancelled.",
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=ExecutionConstants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecutionConstants.js","sourceRoot":"","sources":["../src/ExecutionConstants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,sBAAsB,EAAE,8CAA8C;IACtE,2BAA2B,EAAE,qCAAqC;IAClE,0BAA0B,EAAE,wCAAwC;IACpE,2BAA2B,EAAE,6BAA6B;IAC1D,oBAAoB,EAAE,kCAAkC;IACxD,yBAAyB,EAAE,4BAA4B;IACvD,kBAAkB,EAAE,qBAAqB;CAC1C,CAAC"}
|
|
@@ -33,4 +33,8 @@ export declare class WorkflowExecutor<TContext> {
|
|
|
33
33
|
* Logic to identify tasks that can be started and run them.
|
|
34
34
|
*/
|
|
35
35
|
private processLoop;
|
|
36
|
+
/**
|
|
37
|
+
* Executes a single task step, handling conditions and status updates.
|
|
38
|
+
*/
|
|
39
|
+
private executeTaskStep;
|
|
36
40
|
}
|
package/dist/WorkflowExecutor.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ExecutionConstants } from "./ExecutionConstants.js";
|
|
1
2
|
/**
|
|
2
3
|
* Handles the execution of the workflow steps.
|
|
3
4
|
* @template TContext The shape of the shared context object.
|
|
@@ -34,7 +35,7 @@ export class WorkflowExecutor {
|
|
|
34
35
|
this.stateManager.initialize(steps);
|
|
35
36
|
// Check if already aborted
|
|
36
37
|
if (signal?.aborted) {
|
|
37
|
-
this.stateManager.cancelAllPending(
|
|
38
|
+
this.stateManager.cancelAllPending(ExecutionConstants.CANCELLED_BEFORE_START);
|
|
38
39
|
const results = this.stateManager.getResults();
|
|
39
40
|
this.eventBus.emit("workflowEnd", { context: this.context, results });
|
|
40
41
|
return results;
|
|
@@ -42,7 +43,7 @@ export class WorkflowExecutor {
|
|
|
42
43
|
const executingPromises = new Set();
|
|
43
44
|
const onAbort = () => {
|
|
44
45
|
// Mark all pending tasks as cancelled
|
|
45
|
-
this.stateManager.cancelAllPending(
|
|
46
|
+
this.stateManager.cancelAllPending(ExecutionConstants.WORKFLOW_CANCELLED);
|
|
46
47
|
};
|
|
47
48
|
if (signal) {
|
|
48
49
|
signal.addEventListener("abort", onAbort);
|
|
@@ -64,7 +65,7 @@ export class WorkflowExecutor {
|
|
|
64
65
|
await Promise.race(executingPromises);
|
|
65
66
|
}
|
|
66
67
|
if (signal?.aborted) {
|
|
67
|
-
this.stateManager.cancelAllPending(
|
|
68
|
+
this.stateManager.cancelAllPending(ExecutionConstants.WORKFLOW_CANCELLED);
|
|
68
69
|
}
|
|
69
70
|
else {
|
|
70
71
|
// After a task finishes, check for new work
|
|
@@ -72,7 +73,7 @@ export class WorkflowExecutor {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
// Ensure everything is accounted for (e.g. if loop exited early)
|
|
75
|
-
this.stateManager.cancelAllPending(
|
|
76
|
+
this.stateManager.cancelAllPending(ExecutionConstants.WORKFLOW_CANCELLED);
|
|
76
77
|
const results = this.stateManager.getResults();
|
|
77
78
|
this.eventBus.emit("workflowEnd", { context: this.context, results });
|
|
78
79
|
return results;
|
|
@@ -101,58 +102,70 @@ export class WorkflowExecutor {
|
|
|
101
102
|
break;
|
|
102
103
|
}
|
|
103
104
|
const step = this.readyQueue.shift();
|
|
104
|
-
const taskPromise = (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
this.stateManager.markSkipped(step, result);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
const result = {
|
|
128
|
-
status: "failure",
|
|
129
|
-
message: error instanceof Error
|
|
130
|
-
? error.message
|
|
131
|
-
: "Condition evaluation failed",
|
|
132
|
-
error: error instanceof Error ? error.message : String(error),
|
|
133
|
-
};
|
|
134
|
-
this.stateManager.markCompleted(step, result);
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
105
|
+
const taskPromise = this.executeTaskStep(step, signal)
|
|
106
|
+
.finally(() => {
|
|
107
|
+
executingPromises.delete(taskPromise);
|
|
108
|
+
// When a task finishes, we try to run more
|
|
109
|
+
this.processLoop(executingPromises, signal);
|
|
110
|
+
});
|
|
111
|
+
executingPromises.add(taskPromise);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Executes a single task step, handling conditions and status updates.
|
|
116
|
+
*/
|
|
117
|
+
async executeTaskStep(step, signal) {
|
|
118
|
+
try {
|
|
119
|
+
if (step.condition) {
|
|
120
|
+
const check = step.condition(this.context);
|
|
121
|
+
const shouldRun = check instanceof Promise ? await check : check;
|
|
137
122
|
if (signal?.aborted) {
|
|
138
123
|
this.stateManager.markCompleted(step, {
|
|
139
124
|
status: "cancelled",
|
|
140
|
-
message:
|
|
125
|
+
message: ExecutionConstants.CANCELLED_DURING_CONDITION,
|
|
141
126
|
});
|
|
142
127
|
return;
|
|
143
128
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
129
|
+
if (!shouldRun) {
|
|
130
|
+
const result = {
|
|
131
|
+
status: "skipped",
|
|
132
|
+
message: ExecutionConstants.SKIPPED_BY_CONDITION,
|
|
133
|
+
};
|
|
134
|
+
this.stateManager.markSkipped(step, result);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const result = {
|
|
141
|
+
status: "failure",
|
|
142
|
+
message: error instanceof Error
|
|
143
|
+
? error.message
|
|
144
|
+
: ExecutionConstants.CONDITION_EVALUATION_FAILED,
|
|
145
|
+
error: error instanceof Error ? error.message : String(error),
|
|
146
|
+
};
|
|
147
|
+
this.stateManager.markCompleted(step, result);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (signal?.aborted) {
|
|
151
|
+
this.stateManager.markCompleted(step, {
|
|
152
|
+
status: "cancelled",
|
|
153
|
+
message: ExecutionConstants.TASK_CANCELLED_BEFORE_START,
|
|
154
154
|
});
|
|
155
|
-
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.stateManager.markRunning(step);
|
|
158
|
+
try {
|
|
159
|
+
const result = await this.strategy.execute(step, this.context, signal);
|
|
160
|
+
this.stateManager.markCompleted(step, result);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
const result = {
|
|
164
|
+
status: "failure",
|
|
165
|
+
message: ExecutionConstants.EXECUTION_STRATEGY_FAILED,
|
|
166
|
+
error: error instanceof Error ? error.message : String(error),
|
|
167
|
+
};
|
|
168
|
+
this.stateManager.markCompleted(step, result);
|
|
156
169
|
}
|
|
157
170
|
}
|
|
158
171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkflowExecutor.js","sourceRoot":"","sources":["../src/WorkflowExecutor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WorkflowExecutor.js","sourceRoot":"","sources":["../src/WorkflowExecutor.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@calmo/task-runner",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.3",
|
|
4
4
|
"description": "A lightweight, type-safe, and domain-agnostic task orchestration engine. It resolves a Directed Acyclic Graph (DAG) of steps, executes independent tasks in parallel, and manages a shared context across the pipeline.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used in the execution engine.
|
|
3
|
+
*/
|
|
4
|
+
export const ExecutionConstants = {
|
|
5
|
+
CANCELLED_BEFORE_START: "Workflow cancelled before execution started.",
|
|
6
|
+
TASK_CANCELLED_BEFORE_START: "Cancelled before execution started.",
|
|
7
|
+
CANCELLED_DURING_CONDITION: "Cancelled during condition evaluation.",
|
|
8
|
+
CONDITION_EVALUATION_FAILED: "Condition evaluation failed",
|
|
9
|
+
SKIPPED_BY_CONDITION: "Skipped by condition evaluation.",
|
|
10
|
+
EXECUTION_STRATEGY_FAILED: "Execution strategy failed.",
|
|
11
|
+
WORKFLOW_CANCELLED: "Workflow cancelled.",
|
|
12
|
+
};
|
package/src/WorkflowExecutor.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { TaskResult } from "./TaskResult.js";
|
|
|
3
3
|
import { EventBus } from "./EventBus.js";
|
|
4
4
|
import { TaskStateManager } from "./TaskStateManager.js";
|
|
5
5
|
import { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";
|
|
6
|
+
import { ExecutionConstants } from "./ExecutionConstants.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Handles the execution of the workflow steps.
|
|
@@ -42,7 +43,7 @@ export class WorkflowExecutor<TContext> {
|
|
|
42
43
|
// Check if already aborted
|
|
43
44
|
if (signal?.aborted) {
|
|
44
45
|
this.stateManager.cancelAllPending(
|
|
45
|
-
|
|
46
|
+
ExecutionConstants.CANCELLED_BEFORE_START
|
|
46
47
|
);
|
|
47
48
|
const results = this.stateManager.getResults();
|
|
48
49
|
this.eventBus.emit("workflowEnd", { context: this.context, results });
|
|
@@ -53,7 +54,7 @@ export class WorkflowExecutor<TContext> {
|
|
|
53
54
|
|
|
54
55
|
const onAbort = () => {
|
|
55
56
|
// Mark all pending tasks as cancelled
|
|
56
|
-
this.stateManager.cancelAllPending(
|
|
57
|
+
this.stateManager.cancelAllPending(ExecutionConstants.WORKFLOW_CANCELLED);
|
|
57
58
|
};
|
|
58
59
|
|
|
59
60
|
if (signal) {
|
|
@@ -80,7 +81,9 @@ export class WorkflowExecutor<TContext> {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
if (signal?.aborted) {
|
|
83
|
-
this.stateManager.cancelAllPending(
|
|
84
|
+
this.stateManager.cancelAllPending(
|
|
85
|
+
ExecutionConstants.WORKFLOW_CANCELLED
|
|
86
|
+
);
|
|
84
87
|
} else {
|
|
85
88
|
// After a task finishes, check for new work
|
|
86
89
|
this.processLoop(executingPromises, signal);
|
|
@@ -88,7 +91,7 @@ export class WorkflowExecutor<TContext> {
|
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
// Ensure everything is accounted for (e.g. if loop exited early)
|
|
91
|
-
this.stateManager.cancelAllPending(
|
|
94
|
+
this.stateManager.cancelAllPending(ExecutionConstants.WORKFLOW_CANCELLED);
|
|
92
95
|
|
|
93
96
|
const results = this.stateManager.getResults();
|
|
94
97
|
this.eventBus.emit("workflowEnd", { context: this.context, results });
|
|
@@ -128,64 +131,79 @@ export class WorkflowExecutor<TContext> {
|
|
|
128
131
|
|
|
129
132
|
const step = this.readyQueue.shift()!;
|
|
130
133
|
|
|
131
|
-
const taskPromise = (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
} catch (error) {
|
|
155
|
-
const result: TaskResult = {
|
|
156
|
-
status: "failure",
|
|
157
|
-
message:
|
|
158
|
-
error instanceof Error
|
|
159
|
-
? error.message
|
|
160
|
-
: "Condition evaluation failed",
|
|
161
|
-
error: error instanceof Error ? error.message : String(error),
|
|
162
|
-
};
|
|
163
|
-
this.stateManager.markCompleted(step, result);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
134
|
+
const taskPromise = this.executeTaskStep(step, signal)
|
|
135
|
+
.finally(() => {
|
|
136
|
+
executingPromises.delete(taskPromise);
|
|
137
|
+
// When a task finishes, we try to run more
|
|
138
|
+
this.processLoop(executingPromises, signal);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
executingPromises.add(taskPromise);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Executes a single task step, handling conditions and status updates.
|
|
147
|
+
*/
|
|
148
|
+
private async executeTaskStep(
|
|
149
|
+
step: TaskStep<TContext>,
|
|
150
|
+
signal?: AbortSignal
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
try {
|
|
153
|
+
if (step.condition) {
|
|
154
|
+
const check = step.condition(this.context);
|
|
155
|
+
const shouldRun = check instanceof Promise ? await check : check;
|
|
166
156
|
|
|
167
157
|
if (signal?.aborted) {
|
|
168
158
|
this.stateManager.markCompleted(step, {
|
|
169
159
|
status: "cancelled",
|
|
170
|
-
message:
|
|
160
|
+
message: ExecutionConstants.CANCELLED_DURING_CONDITION,
|
|
171
161
|
});
|
|
172
162
|
return;
|
|
173
163
|
}
|
|
174
164
|
|
|
175
|
-
|
|
165
|
+
if (!shouldRun) {
|
|
166
|
+
const result: TaskResult = {
|
|
167
|
+
status: "skipped",
|
|
168
|
+
message: ExecutionConstants.SKIPPED_BY_CONDITION,
|
|
169
|
+
};
|
|
170
|
+
this.stateManager.markSkipped(step, result);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
const result: TaskResult = {
|
|
176
|
+
status: "failure",
|
|
177
|
+
message:
|
|
178
|
+
error instanceof Error
|
|
179
|
+
? error.message
|
|
180
|
+
: ExecutionConstants.CONDITION_EVALUATION_FAILED,
|
|
181
|
+
error: error instanceof Error ? error.message : String(error),
|
|
182
|
+
};
|
|
183
|
+
this.stateManager.markCompleted(step, result);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
176
186
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
});
|
|
182
|
-
})().finally(() => {
|
|
183
|
-
executingPromises.delete(taskPromise);
|
|
184
|
-
// When a task finishes, we try to run more
|
|
185
|
-
this.processLoop(executingPromises, signal);
|
|
187
|
+
if (signal?.aborted) {
|
|
188
|
+
this.stateManager.markCompleted(step, {
|
|
189
|
+
status: "cancelled",
|
|
190
|
+
message: ExecutionConstants.TASK_CANCELLED_BEFORE_START,
|
|
186
191
|
});
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
187
194
|
|
|
188
|
-
|
|
195
|
+
this.stateManager.markRunning(step);
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const result = await this.strategy.execute(step, this.context, signal);
|
|
199
|
+
this.stateManager.markCompleted(step, result);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
const result: TaskResult = {
|
|
202
|
+
status: "failure",
|
|
203
|
+
message: ExecutionConstants.EXECUTION_STRATEGY_FAILED,
|
|
204
|
+
error: error instanceof Error ? error.message : String(error),
|
|
205
|
+
};
|
|
206
|
+
this.stateManager.markCompleted(step, result);
|
|
189
207
|
}
|
|
190
208
|
}
|
|
191
209
|
}
|