@calmo/task-runner 3.8.2 → 3.8.4
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/AGENTS.md +2 -0
- package/CHANGELOG.md +10 -0
- package/coverage/coverage-final.json +5 -4
- 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 +4 -10
- 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 +202 -189
- 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 +4 -10
- 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/TaskGraphValidator.js +2 -4
- package/dist/TaskGraphValidator.js.map +1 -1
- package/dist/WorkflowExecutor.d.ts +4 -0
- package/dist/WorkflowExecutor.js +62 -49
- package/dist/WorkflowExecutor.js.map +1 -1
- package/openspec/changes/feat-continue-on-error/proposal.md +20 -0
- package/openspec/changes/feat-continue-on-error/tasks.md +17 -0
- package/package.json +1 -1
- package/src/ExecutionConstants.ts +12 -0
- package/src/TaskGraphValidator.ts +2 -4
- package/src/WorkflowExecutor.ts +69 -51
- package/test-report.xml +146 -140
|
@@ -103,8 +103,7 @@ export class TaskGraphValidator {
|
|
|
103
103
|
stack.push({
|
|
104
104
|
taskId: startTaskId,
|
|
105
105
|
index: 0,
|
|
106
|
-
|
|
107
|
-
dependencies: adjacencyList.get(startTaskId) ?? [],
|
|
106
|
+
dependencies: adjacencyList.get(startTaskId),
|
|
108
107
|
});
|
|
109
108
|
while (stack.length > 0) {
|
|
110
109
|
const frame = stack[stack.length - 1];
|
|
@@ -124,8 +123,7 @@ export class TaskGraphValidator {
|
|
|
124
123
|
stack.push({
|
|
125
124
|
taskId: dependenceId,
|
|
126
125
|
index: 0,
|
|
127
|
-
|
|
128
|
-
dependencies: adjacencyList.get(dependenceId) ?? [],
|
|
126
|
+
dependencies: adjacencyList.get(dependenceId),
|
|
129
127
|
});
|
|
130
128
|
}
|
|
131
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskGraphValidator.js","sourceRoot":"","sources":["../src/TaskGraphValidator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"TaskGraphValidator.js","sourceRoot":"","sources":["../src/TaskGraphValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -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":"AAKA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAWjB;IACA;IACA;IACA;IACA;IAdF,UAAU,GAAyB,EAAE,CAAC;IAE9C;;;;;;OAMG;IACH,YACU,OAAiB,EACjB,QAA4B,EAC5B,YAAwC,EACxC,QAAsC,EACtC,WAAoB;QAJpB,YAAO,GAAP,OAAO,CAAU;QACjB,aAAQ,GAAR,QAAQ,CAAoB;QAC5B,iBAAY,GAAZ,YAAY,CAA4B;QACxC,aAAQ,GAAR,QAAQ,CAA8B;QACtC,gBAAW,GAAX,WAAW,CAAS;IAC3B,CAAC;IAEJ;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CACX,KAA2B,EAC3B,MAAoB;QAEpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEpC,2BAA2B;QAC3B,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAChC,kBAAkB,CAAC,sBAAsB,CAC1C,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;YAC/C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACtE,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAiB,CAAC;QAEnD,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,sCAAsC;YACtC,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,CAAC,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,CAAC;YACH,eAAe;YACf,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;YAE5C,OACE,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE;gBACnC,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE;gBACnC,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAC1B,CAAC;gBACD,yEAAyE;gBACzE,8DAA8D;gBAC9D,2EAA2E;gBAC3E,IAAI,iBAAiB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACjC,MAAM;gBACR,CAAC;qBAAM,CAAC;oBACN,mCAAmC;oBACnC,MAAM,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACxC,CAAC;gBAED,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;oBACpB,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAChC,kBAAkB,CAAC,kBAAkB,CACtC,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,4CAA4C;oBAC5C,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;YAED,iEAAiE;YACjE,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;YAE1E,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;YAC/C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACtE,OAAO,OAAO,CAAC;QACjB,CAAC;gBAAS,CAAC;YACT,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,WAAW,CACjB,iBAAqC,EACrC,MAAoB;QAEpB,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAC;QAE3D,qCAAqC;QACrC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAED,4DAA4D;QAC5D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;QAEtE,yDAAyD;QACzD,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,IACE,IAAI,CAAC,WAAW,KAAK,SAAS;gBAC9B,iBAAiB,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,EAC1C,CAAC;gBACD,MAAM;YACR,CAAC;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAG,CAAC;YAEtC,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC;iBACnD,OAAO,CAAC,GAAG,EAAE;gBACZ,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gBACtC,2CAA2C;gBAC3C,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;YAC9C,CAAC,CAAC,CAAC;YAEL,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CAC3B,IAAwB,EACxB,MAAoB;QAEpB,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC3C,MAAM,SAAS,GAAG,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;gBAEjE,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;oBACpB,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE;wBACpC,MAAM,EAAE,WAAW;wBACnB,OAAO,EAAE,kBAAkB,CAAC,0BAA0B;qBACvD,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,MAAM,GAAe;wBACzB,MAAM,EAAE,SAAS;wBACjB,OAAO,EAAE,kBAAkB,CAAC,oBAAoB;qBACjD,CAAC;oBACF,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBAC5C,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAe;gBACzB,MAAM,EAAE,SAAS;gBACjB,OAAO,EACL,KAAK,YAAY,KAAK;oBACpB,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,kBAAkB,CAAC,2BAA2B;gBACpD,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CAAC;YACF,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE;gBACpC,MAAM,EAAE,WAAW;gBACnB,OAAO,EAAE,kBAAkB,CAAC,2BAA2B;aACxD,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAEpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACvE,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAe;gBACzB,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,kBAAkB,CAAC,yBAAyB;gBACrD,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CAAC;YACF,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Change: Continue On Error
|
|
2
|
+
|
|
3
|
+
## Why
|
|
4
|
+
|
|
5
|
+
Currently, if a task fails, all tasks that depend on it are automatically skipped. This is a safe default, but it prevents users from defining "non-critical" tasks (e.g., "Cleanup Temp Files", "Send Optional Notification") that should not block the workflow if they fail. Users often want downstream tasks to continue executing even if a specific non-essential dependency fails.
|
|
6
|
+
|
|
7
|
+
## What Changes
|
|
8
|
+
|
|
9
|
+
- Update `TaskStep` interface to include an optional `continueOnError: boolean` property (defaulting to `false`).
|
|
10
|
+
- Update `TaskStateManager` to be aware of task definitions.
|
|
11
|
+
- Update `TaskStateManager.processDependencies` logic:
|
|
12
|
+
- If a dependency failed but has `continueOnError: true`, treat it as "satisfied" for the purpose of unblocking dependents.
|
|
13
|
+
- The dependent task will execute as if the dependency succeeded.
|
|
14
|
+
- The failed task's result remains `status: "failure"`, preserving visibility of the error.
|
|
15
|
+
|
|
16
|
+
## Impact
|
|
17
|
+
|
|
18
|
+
- Affected specs: `001-generic-task-runner`
|
|
19
|
+
- Affected code: `src/TaskStep.ts`, `src/TaskStateManager.ts`
|
|
20
|
+
- **Non-breaking change**: The default behavior remains (stop on error). Users must opt-in by setting the flag.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Tasks: Continue On Error
|
|
2
|
+
|
|
3
|
+
- [ ] **Update TaskStep Interface**
|
|
4
|
+
- [ ] Add `continueOnError?: boolean` to `TaskStep<TContext>` in `src/TaskStep.ts`.
|
|
5
|
+
- [ ] Update documentation comments for the new property.
|
|
6
|
+
|
|
7
|
+
- [ ] **Update TaskStateManager**
|
|
8
|
+
- [ ] Modify `TaskStateManager` to store the full `TaskStep` definitions map (name -> step) during initialization (`initialize` method).
|
|
9
|
+
- [ ] Update `processDependencies` to check `continueOnError` property when a dependency is in "failure" state.
|
|
10
|
+
- [ ] If `continueOnError` is true, allow the dependent task to proceed (do not mark as skipped).
|
|
11
|
+
|
|
12
|
+
- [ ] **Tests**
|
|
13
|
+
- [ ] Create a new test file `tests/continueOnError.test.ts`.
|
|
14
|
+
- [ ] Test case: Task A fails (default) -> Task B is skipped. (Regression check)
|
|
15
|
+
- [ ] Test case: Task A fails (continueOnError: true) -> Task B runs.
|
|
16
|
+
- [ ] Test case: Task A fails (continueOnError: true) -> Task B runs -> Task C runs.
|
|
17
|
+
- [ ] Test case: Task A fails (continueOnError: true) -> Task B fails (continueOnError: false) -> Task C skipped.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@calmo/task-runner",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.4",
|
|
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
|
+
};
|
|
@@ -145,8 +145,7 @@ export class TaskGraphValidator implements ITaskGraphValidator {
|
|
|
145
145
|
stack.push({
|
|
146
146
|
taskId: startTaskId,
|
|
147
147
|
index: 0,
|
|
148
|
-
|
|
149
|
-
dependencies: adjacencyList.get(startTaskId) ?? [],
|
|
148
|
+
dependencies: adjacencyList.get(startTaskId)!,
|
|
150
149
|
});
|
|
151
150
|
|
|
152
151
|
while (stack.length > 0) {
|
|
@@ -171,8 +170,7 @@ export class TaskGraphValidator implements ITaskGraphValidator {
|
|
|
171
170
|
stack.push({
|
|
172
171
|
taskId: dependenceId,
|
|
173
172
|
index: 0,
|
|
174
|
-
|
|
175
|
-
dependencies: adjacencyList.get(dependenceId) ?? [],
|
|
173
|
+
dependencies: adjacencyList.get(dependenceId)!,
|
|
176
174
|
});
|
|
177
175
|
}
|
|
178
176
|
} else {
|
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
|
}
|