@workglow/task-graph 0.0.52
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/LICENSE +201 -0
- package/README.md +1280 -0
- package/dist/browser.d.ts +7 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +2842 -0
- package/dist/browser.js.map +33 -0
- package/dist/bun.d.ts +7 -0
- package/dist/bun.d.ts.map +1 -0
- package/dist/bun.js +2843 -0
- package/dist/bun.js.map +33 -0
- package/dist/common.d.ts +33 -0
- package/dist/common.d.ts.map +1 -0
- package/dist/node.d.ts +7 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +2842 -0
- package/dist/node.js.map +33 -0
- package/dist/storage/TaskGraphRepository.d.ts +92 -0
- package/dist/storage/TaskGraphRepository.d.ts.map +1 -0
- package/dist/storage/TaskGraphTabularRepository.d.ts +73 -0
- package/dist/storage/TaskGraphTabularRepository.d.ts.map +1 -0
- package/dist/storage/TaskOutputRepository.d.ts +93 -0
- package/dist/storage/TaskOutputRepository.d.ts.map +1 -0
- package/dist/storage/TaskOutputTabularRepository.d.ts +84 -0
- package/dist/storage/TaskOutputTabularRepository.d.ts.map +1 -0
- package/dist/task/ArrayTask.d.ts +72 -0
- package/dist/task/ArrayTask.d.ts.map +1 -0
- package/dist/task/ConditionalTask.d.ts +278 -0
- package/dist/task/ConditionalTask.d.ts.map +1 -0
- package/dist/task/GraphAsTask.d.ts +79 -0
- package/dist/task/GraphAsTask.d.ts.map +1 -0
- package/dist/task/GraphAsTaskRunner.d.ts +36 -0
- package/dist/task/GraphAsTaskRunner.d.ts.map +1 -0
- package/dist/task/ITask.d.ts +144 -0
- package/dist/task/ITask.d.ts.map +1 -0
- package/dist/task/ITaskRunner.d.ts +36 -0
- package/dist/task/ITaskRunner.d.ts.map +1 -0
- package/dist/task/JobQueueFactory.d.ts +23 -0
- package/dist/task/JobQueueFactory.d.ts.map +1 -0
- package/dist/task/JobQueueTask.d.ts +65 -0
- package/dist/task/JobQueueTask.d.ts.map +1 -0
- package/dist/task/Task.d.ts +334 -0
- package/dist/task/Task.d.ts.map +1 -0
- package/dist/task/TaskError.d.ts +66 -0
- package/dist/task/TaskError.d.ts.map +1 -0
- package/dist/task/TaskEvents.d.ts +40 -0
- package/dist/task/TaskEvents.d.ts.map +1 -0
- package/dist/task/TaskJSON.d.ts +82 -0
- package/dist/task/TaskJSON.d.ts.map +1 -0
- package/dist/task/TaskQueueRegistry.d.ts +69 -0
- package/dist/task/TaskQueueRegistry.d.ts.map +1 -0
- package/dist/task/TaskRegistry.d.ts +31 -0
- package/dist/task/TaskRegistry.d.ts.map +1 -0
- package/dist/task/TaskRunner.d.ts +99 -0
- package/dist/task/TaskRunner.d.ts.map +1 -0
- package/dist/task/TaskTypes.d.ts +68 -0
- package/dist/task/TaskTypes.d.ts.map +1 -0
- package/dist/task-graph/Conversions.d.ts +28 -0
- package/dist/task-graph/Conversions.d.ts.map +1 -0
- package/dist/task-graph/Dataflow.d.ts +73 -0
- package/dist/task-graph/Dataflow.d.ts.map +1 -0
- package/dist/task-graph/DataflowEvents.d.ts +34 -0
- package/dist/task-graph/DataflowEvents.d.ts.map +1 -0
- package/dist/task-graph/ITaskGraph.d.ts +38 -0
- package/dist/task-graph/ITaskGraph.d.ts.map +1 -0
- package/dist/task-graph/IWorkflow.d.ts +13 -0
- package/dist/task-graph/IWorkflow.d.ts.map +1 -0
- package/dist/task-graph/TaskGraph.d.ts +230 -0
- package/dist/task-graph/TaskGraph.d.ts.map +1 -0
- package/dist/task-graph/TaskGraphEvents.d.ts +54 -0
- package/dist/task-graph/TaskGraphEvents.d.ts.map +1 -0
- package/dist/task-graph/TaskGraphRunner.d.ts +202 -0
- package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -0
- package/dist/task-graph/TaskGraphScheduler.d.ts +56 -0
- package/dist/task-graph/TaskGraphScheduler.d.ts.map +1 -0
- package/dist/task-graph/Workflow.d.ts +155 -0
- package/dist/task-graph/Workflow.d.ts.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +59 -0
- package/src/storage/README.md +61 -0
- package/src/task/ConditionalTask.README.md +268 -0
- package/src/task/README.md +251 -0
- package/src/task-graph/README.md +142 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { EventEmitter, type EventParameters } from "@workglow/util";
|
|
7
|
+
import { TaskOutputRepository } from "../storage/TaskOutputRepository";
|
|
8
|
+
import { GraphAsTask } from "../task/GraphAsTask";
|
|
9
|
+
import type { ITask, ITaskConstructor } from "../task/ITask";
|
|
10
|
+
import { Task } from "../task/Task";
|
|
11
|
+
import type { JsonTaskItem, TaskGraphJson } from "../task/TaskJSON";
|
|
12
|
+
import { DataPorts, TaskConfig } from "../task/TaskTypes";
|
|
13
|
+
import { PipeFunction, Taskish } from "./Conversions";
|
|
14
|
+
import { IWorkflow } from "./IWorkflow";
|
|
15
|
+
import { TaskGraph } from "./TaskGraph";
|
|
16
|
+
import { CompoundMergeStrategy, type PropertyArrayGraphResult } from "./TaskGraphRunner";
|
|
17
|
+
export type CreateWorkflow<I extends DataPorts, _O extends DataPorts, C extends TaskConfig> = (input?: Partial<I>, config?: Partial<C>) => Workflow;
|
|
18
|
+
export type WorkflowEventListeners = {
|
|
19
|
+
changed: (id: unknown) => void;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
error: (error: string) => void;
|
|
22
|
+
start: () => void;
|
|
23
|
+
complete: () => void;
|
|
24
|
+
abort: (error: string) => void;
|
|
25
|
+
};
|
|
26
|
+
export type WorkflowEvents = keyof WorkflowEventListeners;
|
|
27
|
+
export type WorkflowEventListener<Event extends WorkflowEvents> = WorkflowEventListeners[Event];
|
|
28
|
+
export type WorkflowEventParameters<Event extends WorkflowEvents> = EventParameters<WorkflowEventListeners, Event>;
|
|
29
|
+
/**
|
|
30
|
+
* Class for building and managing a task graph
|
|
31
|
+
* Provides methods for adding tasks, connecting outputs to inputs, and running the task graph
|
|
32
|
+
*/
|
|
33
|
+
export declare class Workflow<Input extends DataPorts = DataPorts, Output extends DataPorts = DataPorts> implements IWorkflow<Input, Output> {
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new Workflow
|
|
36
|
+
*
|
|
37
|
+
* @param repository - Optional repository for task outputs
|
|
38
|
+
*/
|
|
39
|
+
constructor(repository?: TaskOutputRepository);
|
|
40
|
+
private _graph;
|
|
41
|
+
private _dataFlows;
|
|
42
|
+
private _error;
|
|
43
|
+
private _repository?;
|
|
44
|
+
private _abortController?;
|
|
45
|
+
/**
|
|
46
|
+
* Event emitter for task graph events
|
|
47
|
+
*/
|
|
48
|
+
readonly events: EventEmitter<WorkflowEventListeners>;
|
|
49
|
+
/**
|
|
50
|
+
* Creates a helper function for adding specific task types to a Workflow
|
|
51
|
+
*
|
|
52
|
+
* @param taskClass - The task class to create a helper for
|
|
53
|
+
* @returns A function that adds the specified task type to a Workflow
|
|
54
|
+
*/
|
|
55
|
+
static createWorkflow<I extends DataPorts, O extends DataPorts, C extends TaskConfig = TaskConfig>(taskClass: ITaskConstructor<I, O, C>): CreateWorkflow<I, O, C>;
|
|
56
|
+
/**
|
|
57
|
+
* Gets the current task graph
|
|
58
|
+
*/
|
|
59
|
+
get graph(): TaskGraph;
|
|
60
|
+
/**
|
|
61
|
+
* Sets a new task graph
|
|
62
|
+
*/
|
|
63
|
+
set graph(value: TaskGraph);
|
|
64
|
+
/**
|
|
65
|
+
* Gets the current error message
|
|
66
|
+
*/
|
|
67
|
+
get error(): string;
|
|
68
|
+
/**
|
|
69
|
+
* Event subscription methods
|
|
70
|
+
*/
|
|
71
|
+
on<Event extends WorkflowEvents>(name: Event, fn: WorkflowEventListener<Event>): void;
|
|
72
|
+
off<Event extends WorkflowEvents>(name: Event, fn: WorkflowEventListener<Event>): void;
|
|
73
|
+
once<Event extends WorkflowEvents>(name: Event, fn: WorkflowEventListener<Event>): void;
|
|
74
|
+
waitOn<Event extends WorkflowEvents>(name: Event): Promise<WorkflowEventParameters<Event>>;
|
|
75
|
+
/**
|
|
76
|
+
* Runs the task graph
|
|
77
|
+
*
|
|
78
|
+
* @param input - The input to the task graph
|
|
79
|
+
* @returns The output of the task graph
|
|
80
|
+
*/
|
|
81
|
+
run(input?: Input): Promise<PropertyArrayGraphResult<Output>>;
|
|
82
|
+
/**
|
|
83
|
+
* Aborts the running task graph
|
|
84
|
+
*/
|
|
85
|
+
abort(): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Removes the last task from the task graph
|
|
88
|
+
*
|
|
89
|
+
* @returns The current task graph workflow
|
|
90
|
+
*/
|
|
91
|
+
pop(): Workflow;
|
|
92
|
+
/**
|
|
93
|
+
* Converts the task graph to JSON
|
|
94
|
+
*
|
|
95
|
+
* @returns The task graph as JSON
|
|
96
|
+
*/
|
|
97
|
+
toJSON(): TaskGraphJson;
|
|
98
|
+
/**
|
|
99
|
+
* Converts the task graph to dependency JSON
|
|
100
|
+
*
|
|
101
|
+
* @returns The task graph as dependency JSON
|
|
102
|
+
*/
|
|
103
|
+
toDependencyJSON(): JsonTaskItem[];
|
|
104
|
+
pipe<A extends DataPorts, B extends DataPorts>(fn1: Taskish<A, B>): IWorkflow<A, B>;
|
|
105
|
+
pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts>(fn1: Taskish<A, B>, fn2: Taskish<B, C>): IWorkflow<A, C>;
|
|
106
|
+
pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts, D extends DataPorts>(fn1: Taskish<A, B>, fn2: Taskish<B, C>, fn3: Taskish<C, D>): IWorkflow<A, D>;
|
|
107
|
+
pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts, D extends DataPorts, E extends DataPorts>(fn1: Taskish<A, B>, fn2: Taskish<B, C>, fn3: Taskish<C, D>, fn4: Taskish<D, E>): IWorkflow<A, E>;
|
|
108
|
+
pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts, D extends DataPorts, E extends DataPorts, F extends DataPorts>(fn1: Taskish<A, B>, fn2: Taskish<B, C>, fn3: Taskish<C, D>, fn4: Taskish<D, E>, fn5: Taskish<E, F>): IWorkflow<A, F>;
|
|
109
|
+
static pipe<A extends DataPorts, B extends DataPorts>(fn1: PipeFunction<A, B> | ITask<A, B>): IWorkflow;
|
|
110
|
+
static pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts>(fn1: PipeFunction<A, B> | ITask<A, B>, fn2: PipeFunction<B, C> | ITask<B, C>): IWorkflow;
|
|
111
|
+
static pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts, D extends DataPorts>(fn1: PipeFunction<A, B> | ITask<A, B>, fn2: PipeFunction<B, C> | ITask<B, C>, fn3: PipeFunction<C, D> | ITask<C, D>): IWorkflow;
|
|
112
|
+
static pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts, D extends DataPorts, E extends DataPorts>(fn1: PipeFunction<A, B> | ITask<A, B>, fn2: PipeFunction<B, C> | ITask<B, C>, fn3: PipeFunction<C, D> | ITask<C, D>, fn4: PipeFunction<D, E> | ITask<D, E>): IWorkflow;
|
|
113
|
+
static pipe<A extends DataPorts, B extends DataPorts, C extends DataPorts, D extends DataPorts, E extends DataPorts, F extends DataPorts>(fn1: PipeFunction<A, B> | ITask<A, B>, fn2: PipeFunction<B, C> | ITask<B, C>, fn3: PipeFunction<C, D> | ITask<C, D>, fn4: PipeFunction<D, E> | ITask<D, E>, fn5: PipeFunction<E, F> | ITask<E, F>): IWorkflow;
|
|
114
|
+
parallel(args: (PipeFunction<any, any> | Task)[], mergeFn?: CompoundMergeStrategy): IWorkflow;
|
|
115
|
+
static parallel(args: (PipeFunction<any, any> | ITask)[], mergeFn?: CompoundMergeStrategy): IWorkflow;
|
|
116
|
+
/**
|
|
117
|
+
* Renames an output of a task to a new target input
|
|
118
|
+
*
|
|
119
|
+
* @param source - The id of the output to rename
|
|
120
|
+
* @param target - The id of the input to rename to
|
|
121
|
+
* @param index - The index of the task to rename the output of, defaults to the last task
|
|
122
|
+
* @returns The current task graph workflow
|
|
123
|
+
*/
|
|
124
|
+
rename(source: string, target: string, index?: number): Workflow;
|
|
125
|
+
toTaskGraph(): TaskGraph;
|
|
126
|
+
toTask(): GraphAsTask;
|
|
127
|
+
/**
|
|
128
|
+
* Resets the task graph workflow to its initial state
|
|
129
|
+
*
|
|
130
|
+
* @returns The current task graph workflow
|
|
131
|
+
*/
|
|
132
|
+
reset(): Workflow;
|
|
133
|
+
/**
|
|
134
|
+
* Sets up event listeners for the task graph
|
|
135
|
+
*/
|
|
136
|
+
private setupEvents;
|
|
137
|
+
/**
|
|
138
|
+
* Clears event listeners for the task graph
|
|
139
|
+
*/
|
|
140
|
+
private clearEvents;
|
|
141
|
+
/**
|
|
142
|
+
* Handles changes to the task graph
|
|
143
|
+
*/
|
|
144
|
+
private _onChanged;
|
|
145
|
+
/**
|
|
146
|
+
* Connects outputs to inputs between tasks
|
|
147
|
+
*/
|
|
148
|
+
connect(sourceTaskId: unknown, sourceTaskPortId: string, targetTaskId: unknown, targetTaskPortId: string): Workflow;
|
|
149
|
+
addTask<I extends DataPorts, O extends DataPorts, C extends TaskConfig = TaskConfig>(taskClass: ITaskConstructor<I, O, C>, input: I, config: C): ITask<I, O, C>;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Helper function for backward compatibility
|
|
153
|
+
*/
|
|
154
|
+
export declare function CreateWorkflow<I extends DataPorts, O extends DataPorts, C extends TaskConfig = TaskConfig>(taskClass: any): CreateWorkflow<I, O, C>;
|
|
155
|
+
//# sourceMappingURL=Workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Workflow.d.ts","sourceRoot":"","sources":["../../src/task-graph/Workflow.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@workglow/task-graph",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.52",
|
|
5
|
+
"description": "Task graph management for Workglow, providing DAG construction, execution planning, and workflow orchestration.",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"watch": "concurrently -c 'auto' 'bun:watch-*'",
|
|
8
|
+
"watch-browser": "bun build --watch --no-clear-screen --target=browser --sourcemap=external --packages=external --outdir ./dist ./src/browser.ts",
|
|
9
|
+
"watch-node": "bun build --watch --no-clear-screen --target=node --sourcemap=external --packages=external --outdir ./dist ./src/node.ts",
|
|
10
|
+
"watch-bun": "bun build --watch --no-clear-screen --target=bun --sourcemap=external --packages=external --outdir ./dist ./src/bun.ts",
|
|
11
|
+
"watch-types": "tsc --watch --preserveWatchOutput",
|
|
12
|
+
"build-package": "bun run build-clean && concurrently -c 'auto' -n 'browser,node,bun,types' 'bun run build-browser' 'bun run build-node' 'bun run build-bun' 'bun run build-types'",
|
|
13
|
+
"build-clean": "rm -fr dist/* tsconfig.tsbuildinfo",
|
|
14
|
+
"build-browser": "bun build --target=browser --sourcemap=external --packages=external --outdir ./dist ./src/browser.ts",
|
|
15
|
+
"build-node": "bun build --target=node --sourcemap=external --packages=external --outdir ./dist ./src/node.ts",
|
|
16
|
+
"build-bun": "bun build --target=bun --sourcemap=external --packages=external --outdir ./dist ./src/bun.ts",
|
|
17
|
+
"build-types": "rm -f tsconfig.tsbuildinfo && tsc",
|
|
18
|
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
19
|
+
"test": "bun test",
|
|
20
|
+
"prepare": "node -e \"const pkg=require('./package.json');pkg.exports['.'].bun='./dist/bun.js';pkg.exports['.'].types='./dist/types.d.ts';require('fs').writeFileSync('package.json',JSON.stringify(pkg,null,2))\""
|
|
21
|
+
},
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"react-native": "./dist/browser.js",
|
|
25
|
+
"browser": "./dist/browser.js",
|
|
26
|
+
"bun": "./dist/bun.js",
|
|
27
|
+
"types": "./dist/types.d.ts",
|
|
28
|
+
"node": "./dist/node.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"src/**/*.md"
|
|
34
|
+
],
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@workglow/job-queue": "0.0.52",
|
|
40
|
+
"@workglow/storage": "0.0.52",
|
|
41
|
+
"@workglow/util": "0.0.52"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"@workglow/job-queue": {
|
|
45
|
+
"optional": false
|
|
46
|
+
},
|
|
47
|
+
"@workglow/storage": {
|
|
48
|
+
"optional": false
|
|
49
|
+
},
|
|
50
|
+
"@workglow/util": {
|
|
51
|
+
"optional": false
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@workglow/job-queue": "0.0.52",
|
|
56
|
+
"@workglow/storage": "0.0.52",
|
|
57
|
+
"@workglow/util": "0.0.52"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Task Graph Storage Module
|
|
2
|
+
|
|
3
|
+
This module provides persistent storage solutions for task graphs and task outputs using various storage backends. The implementation follows a repository pattern with multiple concrete implementations for different storage technologies.
|
|
4
|
+
|
|
5
|
+
- [Task Output Repositories](#task-output-repositories)
|
|
6
|
+
- [Task Graph Repositories](#task-graph-repositories)
|
|
7
|
+
- [Testing](#testing)
|
|
8
|
+
- [Architecture Notes](#architecture-notes)
|
|
9
|
+
- [License](#license)
|
|
10
|
+
|
|
11
|
+
## Task Output Repositories
|
|
12
|
+
|
|
13
|
+
TaskOutputRepository is a repository for task caching. If a task has the same input it is assumed to return the same output. The task graph runner does not resume, but you can quickly get to the aborted state by using the output repository and re-running the task graph.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// Example usage
|
|
17
|
+
import { SqliteTaskOutputRepository } from "@workglow/test"; // pre-bound implementation for sqlite
|
|
18
|
+
const outputRepo = new SqliteTaskOutputRepository(":memory:");
|
|
19
|
+
await outputRepo.saveOutput("MyTaskType", { param: "value" }, { result: "data" });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Task Graph Repositories
|
|
23
|
+
|
|
24
|
+
TaskGraphRepository is a repository for task graphs themselves. It is used to save and load task graphs.
|
|
25
|
+
|
|
26
|
+
The `TaskGraphRepository` class provides:
|
|
27
|
+
|
|
28
|
+
- CRUD operations for task graphs
|
|
29
|
+
- Event emitters for storage operations
|
|
30
|
+
- Serialization/deserialization of task graphs with data flows
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// Example usage
|
|
34
|
+
import { SqliteTaskGraphRepository } from "@workglow/test"; // pre-bound implementation for sqlite
|
|
35
|
+
const fsRepo = new FsFolderTaskGraphRepository("./storage");
|
|
36
|
+
const memoryRepo = new InMemoryTaskGraphRepository();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Testing
|
|
40
|
+
|
|
41
|
+
Tests are written using Bun test runner. To run tests:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bun test
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Tests include:
|
|
48
|
+
|
|
49
|
+
- Generic repository tests that run against all implementations
|
|
50
|
+
- Storage-specific test suites
|
|
51
|
+
|
|
52
|
+
## Architecture Notes
|
|
53
|
+
|
|
54
|
+
- All repositories use a TabularRepository pattern internally
|
|
55
|
+
- Schema definitions are centralized in `TaskGraphSchema`/`TaskOutputSchema`
|
|
56
|
+
- Primary key configurations are managed through `PrimaryKeyNames` constants
|
|
57
|
+
- Event emitters provide hooks for monitoring repository operations
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
Apache 2.0 - See LICENSE file for details
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# ConditionalTask
|
|
2
|
+
|
|
3
|
+
A task that implements conditional branching within a task graph, similar to if/then/else or switch/case statements.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`ConditionalTask` evaluates configured conditions against its input and selectively enables output ports for active branches. Inactive branches result in `DISABLED` status for their downstream dataflows, which cascades to disable unreachable downstream tasks.
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- **Condition-based routing**: Route data to different downstream tasks based on input values
|
|
12
|
+
- **Exclusive mode (default)**: Act as a switch/case where only the first matching branch activates
|
|
13
|
+
- **Multi-path mode**: Enable multiple branches simultaneously when conditions match
|
|
14
|
+
- **Default branch**: Specify a fallback branch when no conditions match
|
|
15
|
+
- **Disabled propagation**: Inactive branches result in DISABLED status for downstream tasks
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
### Simple If/Else
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { ConditionalTask, TaskGraph, Dataflow } from "@workglow/task-graph";
|
|
23
|
+
|
|
24
|
+
const conditional = new ConditionalTask(
|
|
25
|
+
{},
|
|
26
|
+
{
|
|
27
|
+
branches: [
|
|
28
|
+
{ id: "high", condition: (i) => i.value > 100, outputPort: "highPath" },
|
|
29
|
+
{ id: "low", condition: (i) => i.value <= 100, outputPort: "lowPath" },
|
|
30
|
+
],
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const highHandler = new SomeTask({}, { id: "highHandler" });
|
|
35
|
+
const lowHandler = new SomeTask({}, { id: "lowHandler" });
|
|
36
|
+
|
|
37
|
+
const graph = new TaskGraph();
|
|
38
|
+
graph.addTasks([conditional, highHandler, lowHandler]);
|
|
39
|
+
graph.addDataflow(new Dataflow(conditional.config.id, "highPath", highHandler.config.id, "*"));
|
|
40
|
+
graph.addDataflow(new Dataflow(conditional.config.id, "lowPath", lowHandler.config.id, "*"));
|
|
41
|
+
|
|
42
|
+
// When value > 100, highHandler runs and lowHandler is DISABLED
|
|
43
|
+
// When value <= 100, lowHandler runs and highHandler is DISABLED
|
|
44
|
+
await graph.run({ value: 150 });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Switch/Case Pattern
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const statusRouter = new ConditionalTask(
|
|
51
|
+
{},
|
|
52
|
+
{
|
|
53
|
+
branches: [
|
|
54
|
+
{ id: "active", condition: (i) => i.status === "active", outputPort: "active" },
|
|
55
|
+
{ id: "pending", condition: (i) => i.status === "pending", outputPort: "pending" },
|
|
56
|
+
{ id: "inactive", condition: (i) => i.status === "inactive", outputPort: "inactive" },
|
|
57
|
+
],
|
|
58
|
+
defaultBranch: "inactive", // Fallback if no match
|
|
59
|
+
exclusive: true, // Only first match activates (default)
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Multi-Path Fan-Out
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const fanOut = new ConditionalTask(
|
|
68
|
+
{},
|
|
69
|
+
{
|
|
70
|
+
branches: [
|
|
71
|
+
{ id: "log", condition: () => true, outputPort: "logger" },
|
|
72
|
+
{ id: "process", condition: () => true, outputPort: "processor" },
|
|
73
|
+
{ id: "archive", condition: (i) => i.shouldArchive, outputPort: "archiver" },
|
|
74
|
+
],
|
|
75
|
+
exclusive: false, // All matching branches activate
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
### BranchConfig
|
|
83
|
+
|
|
84
|
+
Each branch in the `branches` array has the following properties:
|
|
85
|
+
|
|
86
|
+
| Property | Type | Description |
|
|
87
|
+
| ------------ | -------------------- | -------------------------------- |
|
|
88
|
+
| `id` | `string` | Unique identifier for the branch |
|
|
89
|
+
| `condition` | `(input) => boolean` | Predicate function to evaluate |
|
|
90
|
+
| `outputPort` | `string` | Output port name for this branch |
|
|
91
|
+
|
|
92
|
+
### ConditionalTaskConfig
|
|
93
|
+
|
|
94
|
+
| Property | Type | Default | Description |
|
|
95
|
+
| --------------- | ---------------- | ----------- | --------------------------------------------- |
|
|
96
|
+
| `branches` | `BranchConfig[]` | Required | Array of branch configurations |
|
|
97
|
+
| `defaultBranch` | `string` | `undefined` | Branch ID to use if no conditions match |
|
|
98
|
+
| `exclusive` | `boolean` | `true` | If true, only first matching branch activates |
|
|
99
|
+
|
|
100
|
+
## Execution Modes
|
|
101
|
+
|
|
102
|
+
### Exclusive Mode (Default)
|
|
103
|
+
|
|
104
|
+
In exclusive mode (`exclusive: true`), branches are evaluated in order and only the first matching branch becomes active. This is similar to a switch/case statement or if/else-if chain.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const router = new ConditionalTask(
|
|
108
|
+
{},
|
|
109
|
+
{
|
|
110
|
+
branches: [
|
|
111
|
+
{ id: "tier1", condition: (i) => i.value > 1000, outputPort: "tier1" },
|
|
112
|
+
{ id: "tier2", condition: (i) => i.value > 100, outputPort: "tier2" },
|
|
113
|
+
{ id: "tier3", condition: (i) => i.value > 0, outputPort: "tier3" },
|
|
114
|
+
],
|
|
115
|
+
exclusive: true,
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// With value = 500:
|
|
120
|
+
// - tier1 condition: 500 > 1000 = false
|
|
121
|
+
// - tier2 condition: 500 > 100 = true ← ACTIVATES, stops here
|
|
122
|
+
// - tier3 is NOT evaluated (exclusive mode)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Multi-Path Mode
|
|
126
|
+
|
|
127
|
+
In multi-path mode (`exclusive: false`), all branches whose conditions evaluate to true become active simultaneously. This enables fan-out patterns.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const multiRouter = new ConditionalTask(
|
|
131
|
+
{},
|
|
132
|
+
{
|
|
133
|
+
branches: [
|
|
134
|
+
{ id: "even", condition: (i) => i.value % 2 === 0, outputPort: "evenPath" },
|
|
135
|
+
{ id: "div3", condition: (i) => i.value % 3 === 0, outputPort: "div3Path" },
|
|
136
|
+
{ id: "div5", condition: (i) => i.value % 5 === 0, outputPort: "div5Path" },
|
|
137
|
+
],
|
|
138
|
+
exclusive: false,
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// With value = 30:
|
|
143
|
+
// - even: 30 % 2 === 0 = true ← ACTIVATES
|
|
144
|
+
// - div3: 30 % 3 === 0 = true ← ACTIVATES
|
|
145
|
+
// - div5: 30 % 5 === 0 = true ← ACTIVATES
|
|
146
|
+
// All three downstream tasks will run!
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Output Behavior
|
|
150
|
+
|
|
151
|
+
For each active branch, the task passes through its entire input to that branch's output port:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// Input: { value: 150, metadata: { source: "api" } }
|
|
155
|
+
|
|
156
|
+
// Output when "high" branch is active:
|
|
157
|
+
{
|
|
158
|
+
_activeBranches: ["high"],
|
|
159
|
+
highPath: { value: 150, metadata: { source: "api" } }
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The `_activeBranches` property is always present and contains the IDs of all active branches.
|
|
164
|
+
|
|
165
|
+
## Dataflow Wiring
|
|
166
|
+
|
|
167
|
+
When wiring ConditionalTask outputs to downstream tasks, use `"*"` (DATAFLOW_ALL_PORTS) as the target port to pass all properties from the branch output:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// Pass all properties from the branch output to the downstream task
|
|
171
|
+
graph.addDataflow(
|
|
172
|
+
new Dataflow(
|
|
173
|
+
conditional.config.id,
|
|
174
|
+
"highPath", // Source port (branch output)
|
|
175
|
+
handler.config.id,
|
|
176
|
+
"*" // Target: all ports (passes { value, metadata, ... })
|
|
177
|
+
)
|
|
178
|
+
);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Disabled Status Propagation
|
|
182
|
+
|
|
183
|
+
When a branch is inactive, its outgoing dataflow is set to `DISABLED` status. The graph runner then propagates this status:
|
|
184
|
+
|
|
185
|
+
1. If ALL incoming dataflows to a task are `DISABLED`, that task becomes `DISABLED`
|
|
186
|
+
2. The disabled task's outgoing dataflows are also set to `DISABLED`
|
|
187
|
+
3. This cascades through the graph until no more tasks can be disabled
|
|
188
|
+
|
|
189
|
+
This ensures that tasks which cannot receive data (because all paths to them are disabled) don't run unnecessarily.
|
|
190
|
+
|
|
191
|
+
## Inspecting Branch Status
|
|
192
|
+
|
|
193
|
+
After execution, you can inspect which branches were activated:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
await conditionalTask.run({ value: 150 });
|
|
197
|
+
|
|
198
|
+
// Check individual branch
|
|
199
|
+
if (conditionalTask.isBranchActive("high")) {
|
|
200
|
+
console.log("High value path was taken");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Get all active branches
|
|
204
|
+
const active = conditionalTask.getActiveBranches();
|
|
205
|
+
console.log("Active branches:", Array.from(active));
|
|
206
|
+
|
|
207
|
+
// Get port status map
|
|
208
|
+
const portStatus = conditionalTask.getPortActiveStatus();
|
|
209
|
+
for (const [port, isActive] of portStatus) {
|
|
210
|
+
console.log(`Port ${port}: ${isActive ? "active" : "inactive"}`);
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Events
|
|
215
|
+
|
|
216
|
+
ConditionalTask emits a custom event after branch evaluation:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
conditionalTask.on("branches_evaluated", (activeBranches: Set<string>) => {
|
|
220
|
+
console.log("Active branches:", Array.from(activeBranches));
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Error Handling
|
|
225
|
+
|
|
226
|
+
If a condition function throws an error, the branch is treated as if the condition returned `false`:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
const router = new ConditionalTask(
|
|
230
|
+
{},
|
|
231
|
+
{
|
|
232
|
+
branches: [
|
|
233
|
+
{
|
|
234
|
+
id: "risky",
|
|
235
|
+
condition: (i) => {
|
|
236
|
+
if (!i.data) throw new Error("No data!");
|
|
237
|
+
return i.data.value > 100;
|
|
238
|
+
},
|
|
239
|
+
outputPort: "risky",
|
|
240
|
+
},
|
|
241
|
+
{ id: "safe", condition: () => true, outputPort: "safe" },
|
|
242
|
+
],
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
// If input.data is undefined:
|
|
247
|
+
// - "risky" condition throws, treated as false
|
|
248
|
+
// - "safe" condition returns true, becomes active
|
|
249
|
+
// Console warning: Condition evaluation failed for branch "risky": Error: No data!
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Integration with Task Graph
|
|
253
|
+
|
|
254
|
+
ConditionalTask integrates seamlessly with TaskGraph and its scheduler:
|
|
255
|
+
|
|
256
|
+
1. ConditionalTask executes and determines active branches
|
|
257
|
+
2. Graph runner sets dataflow status based on branch activation
|
|
258
|
+
3. Scheduler respects DISABLED status when determining ready tasks
|
|
259
|
+
4. Downstream tasks on disabled branches never execute
|
|
260
|
+
|
|
261
|
+
This makes ConditionalTask ideal for implementing:
|
|
262
|
+
|
|
263
|
+
- Feature flags
|
|
264
|
+
- A/B testing
|
|
265
|
+
- Error handling and retry logic
|
|
266
|
+
- Priority-based routing
|
|
267
|
+
- Validation pipelines
|
|
268
|
+
- Any workflow that requires conditional execution paths
|