@push.rocks/taskbuffer 3.2.0 โ 3.4.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/LICENSE +1 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_web/ts/index.d.ts +13 -0
- package/dist_ts_web/ts/index.js +12 -0
- package/dist_ts_web/ts/taskbuffer.classes.bufferrunner.d.ts +8 -0
- package/dist_ts_web/ts/taskbuffer.classes.bufferrunner.js +28 -0
- package/dist_ts_web/ts/taskbuffer.classes.cyclecounter.d.ts +13 -0
- package/dist_ts_web/ts/taskbuffer.classes.cyclecounter.js +31 -0
- package/dist_ts_web/ts/taskbuffer.classes.distributedcoordinator.d.ts +27 -0
- package/dist_ts_web/ts/taskbuffer.classes.distributedcoordinator.js +5 -0
- package/dist_ts_web/ts/taskbuffer.classes.task.d.ts +86 -0
- package/dist_ts_web/ts/taskbuffer.classes.task.js +257 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskchain.d.ts +14 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskchain.js +51 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskdebounced.d.ts +10 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskdebounced.js +20 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskmanager.d.ts +49 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskmanager.js +208 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskonce.d.ts +11 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskonce.js +20 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskparallel.d.ts +7 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskparallel.js +23 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskrunner.d.ts +30 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskrunner.js +54 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskstep.d.ts +27 -0
- package/dist_ts_web/ts/taskbuffer.classes.taskstep.js +37 -0
- package/dist_ts_web/ts/taskbuffer.interfaces.d.ts +36 -0
- package/dist_ts_web/ts/taskbuffer.interfaces.js +2 -0
- package/dist_ts_web/ts/taskbuffer.logging.d.ts +2 -0
- package/dist_ts_web/ts/taskbuffer.logging.js +3 -0
- package/dist_ts_web/ts/taskbuffer.plugins.d.ts +8 -0
- package/dist_ts_web/ts/taskbuffer.plugins.js +9 -0
- package/dist_ts_web/ts_web/00_commitinfo_data.d.ts +8 -0
- package/dist_ts_web/ts_web/00_commitinfo_data.js +9 -0
- package/dist_ts_web/ts_web/demorunner.d.ts +1 -0
- package/dist_ts_web/ts_web/demorunner.js +33 -0
- package/dist_ts_web/ts_web/elements/taskbuffer-dashboard.demo.d.ts +2 -0
- package/dist_ts_web/ts_web/elements/taskbuffer-dashboard.demo.js +285 -0
- package/dist_ts_web/ts_web/index.d.ts +2 -0
- package/dist_ts_web/ts_web/index.js +3 -0
- package/dist_ts_web/ts_web/taskbuffer-dashboard.d.ts +24 -0
- package/dist_ts_web/ts_web/taskbuffer-dashboard.js +557 -0
- package/package.json +5 -4
- package/readme.md +412 -938
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/taskbuffer-dashboard.demo.ts +311 -0
- package/ts_web/index.ts +12 -0
- package/ts_web/taskbuffer-dashboard.ts +541 -0
package/readme.md
CHANGED
|
@@ -1,1112 +1,586 @@
|
|
|
1
1
|
# @push.rocks/taskbuffer ๐
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Modern TypeScript task orchestration with smart buffering, scheduling, and real-time progress tracking**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@push.rocks/taskbuffer)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
## ๐ Features
|
|
10
|
+
|
|
11
|
+
- **๐ฏ Type-Safe Task Management** - Full TypeScript support with generics and type inference
|
|
12
|
+
- **๐ Real-Time Progress Tracking** - Step-based progress with percentage weights
|
|
13
|
+
- **โก Smart Buffering** - Intelligent request debouncing and batching
|
|
14
|
+
- **โฐ Cron Scheduling** - Schedule tasks with cron expressions
|
|
15
|
+
- **๐ Task Chains & Parallel Execution** - Sequential and parallel task orchestration
|
|
16
|
+
- **๐จ Web Component Dashboard** - Real-time visualization of task execution
|
|
17
|
+
- **๐ Comprehensive Metadata** - Track execution history, duration, and status
|
|
18
|
+
- **๐ Thread-Safe Operations** - Concurrency control and execution limits
|
|
19
|
+
- **๐ญ Event-Driven Architecture** - Observable task lifecycle events
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
## ๐ฆ Installation
|
|
12
22
|
|
|
13
23
|
```bash
|
|
24
|
+
npm install @push.rocks/taskbuffer
|
|
25
|
+
# or
|
|
14
26
|
pnpm add @push.rocks/taskbuffer
|
|
27
|
+
# or
|
|
28
|
+
yarn add @push.rocks/taskbuffer
|
|
15
29
|
```
|
|
16
30
|
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
In the modern JavaScript ecosystem, managing asynchronous tasks efficiently is crucial. Whether you're building a data pipeline, managing API rate limits, or orchestrating complex workflows, **@push.rocks/taskbuffer** provides the tools you need:
|
|
20
|
-
|
|
21
|
-
- **๐ฏ TypeScript-first**: Built with TypeScript for TypeScript - enjoy complete type safety and excellent IDE support
|
|
22
|
-
- **โก Flexible execution**: From simple tasks to complex parallel workflows with dependencies
|
|
23
|
-
- **๐ Smart buffering**: Control concurrent executions with intelligent buffer management
|
|
24
|
-
- **โฐ Built-in scheduling**: Cron-based task scheduling without additional dependencies
|
|
25
|
-
- **๐ญ Multiple paradigms**: Support for debounced, throttled, and one-time execution patterns
|
|
26
|
-
- **๐ Progress tracking**: Real-time step-by-step progress monitoring for UI integration
|
|
27
|
-
- **๐ Extensible**: Clean architecture that's easy to extend and customize
|
|
28
|
-
- **๐ Zero dependencies on external schedulers**: Everything you need is included
|
|
29
|
-
|
|
30
|
-
## Core Concepts ๐
|
|
31
|
-
|
|
32
|
-
### Task
|
|
33
|
-
The fundamental unit of work. A task wraps an asynchronous function and provides powerful execution control, now with step-by-step progress tracking.
|
|
34
|
-
|
|
35
|
-
### Taskchain
|
|
36
|
-
Sequential task execution - tasks run one after another, with results passed along the chain.
|
|
37
|
-
|
|
38
|
-
### Taskparallel
|
|
39
|
-
Parallel task execution - multiple tasks run simultaneously for maximum performance.
|
|
40
|
-
|
|
41
|
-
### TaskManager
|
|
42
|
-
Centralized task scheduling and management using cron expressions, with rich metadata collection.
|
|
43
|
-
|
|
44
|
-
### TaskDebounced
|
|
45
|
-
Debounced task execution - prevents rapid repeated executions, only running after a quiet period.
|
|
31
|
+
## ๐ Quick Start
|
|
46
32
|
|
|
47
|
-
###
|
|
48
|
-
Singleton task execution - ensures a task runs exactly once, perfect for initialization routines.
|
|
49
|
-
|
|
50
|
-
### TaskStep ๐
|
|
51
|
-
Granular progress tracking - define named steps with percentage weights for real-time progress monitoring.
|
|
52
|
-
|
|
53
|
-
## Quick Start ๐
|
|
54
|
-
|
|
55
|
-
### Basic Task Execution
|
|
33
|
+
### Basic Task Creation
|
|
56
34
|
|
|
57
35
|
```typescript
|
|
58
|
-
import { Task } from '@push.rocks/taskbuffer';
|
|
36
|
+
import { Task, TaskManager } from '@push.rocks/taskbuffer';
|
|
59
37
|
|
|
60
38
|
// Create a simple task
|
|
61
|
-
const
|
|
62
|
-
name: '
|
|
63
|
-
taskFunction: async () => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
39
|
+
const dataProcessor = new Task({
|
|
40
|
+
name: 'ProcessData',
|
|
41
|
+
taskFunction: async (data) => {
|
|
42
|
+
console.log(`Processing: ${data}`);
|
|
43
|
+
// Your async logic here
|
|
44
|
+
return `Processed: ${data}`;
|
|
45
|
+
}
|
|
67
46
|
});
|
|
68
47
|
|
|
69
48
|
// Execute the task
|
|
70
|
-
const result = await
|
|
49
|
+
const result = await dataProcessor.trigger('my-data');
|
|
50
|
+
console.log(result); // "Processed: my-data"
|
|
71
51
|
```
|
|
72
52
|
|
|
73
|
-
###
|
|
74
|
-
|
|
75
|
-
Track granular progress for complex operations - perfect for UI progress bars:
|
|
53
|
+
### Tasks with Progress Tracking ๐
|
|
76
54
|
|
|
77
55
|
```typescript
|
|
78
|
-
const
|
|
79
|
-
name: '
|
|
56
|
+
const deploymentTask = new Task({
|
|
57
|
+
name: 'DeployApplication',
|
|
80
58
|
steps: [
|
|
81
|
-
{ name: '
|
|
82
|
-
{ name: '
|
|
83
|
-
{ name: '
|
|
84
|
-
{ name: '
|
|
85
|
-
] as const, // Use 'as const' for
|
|
86
|
-
taskFunction: async (
|
|
59
|
+
{ name: 'build', description: 'Building application', percentage: 30 },
|
|
60
|
+
{ name: 'test', description: 'Running tests', percentage: 20 },
|
|
61
|
+
{ name: 'deploy', description: 'Deploying to server', percentage: 40 },
|
|
62
|
+
{ name: 'verify', description: 'Verifying deployment', percentage: 10 }
|
|
63
|
+
] as const, // Use 'as const' for type inference
|
|
64
|
+
taskFunction: async function() {
|
|
87
65
|
// TypeScript knows these step names!
|
|
88
|
-
|
|
89
|
-
|
|
66
|
+
this.notifyStep('build');
|
|
67
|
+
await buildApplication();
|
|
90
68
|
|
|
91
|
-
|
|
92
|
-
|
|
69
|
+
this.notifyStep('test');
|
|
70
|
+
await runTests();
|
|
93
71
|
|
|
94
|
-
|
|
95
|
-
|
|
72
|
+
this.notifyStep('deploy');
|
|
73
|
+
await deployToServer();
|
|
96
74
|
|
|
97
|
-
|
|
98
|
-
|
|
75
|
+
this.notifyStep('verify');
|
|
76
|
+
await verifyDeployment();
|
|
99
77
|
|
|
100
|
-
return
|
|
78
|
+
return 'Deployment successful!';
|
|
101
79
|
}
|
|
102
80
|
});
|
|
103
81
|
|
|
104
|
-
// Monitor progress
|
|
105
|
-
|
|
106
|
-
console.log(
|
|
82
|
+
// Monitor progress
|
|
83
|
+
console.log(deploymentTask.getProgress()); // 0-100
|
|
84
|
+
console.log(deploymentTask.getStepsMetadata()); // Detailed step info
|
|
107
85
|
```
|
|
108
86
|
|
|
109
|
-
##
|
|
87
|
+
## ๐ฏ Core Concepts
|
|
110
88
|
|
|
111
|
-
|
|
89
|
+
### Task Buffering - Intelligent Request Management
|
|
112
90
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
Tasks support generic type parameters for both input and output types:
|
|
91
|
+
TaskBuffer's buffering system prevents overwhelming your system with rapid-fire requests:
|
|
116
92
|
|
|
117
93
|
```typescript
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
interface ProcessedUser {
|
|
128
|
-
userId: string;
|
|
129
|
-
displayName: string;
|
|
130
|
-
normalized: boolean;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Create strongly typed tasks
|
|
134
|
-
const processUserTask = new Task<ProcessedUser>({
|
|
135
|
-
name: 'ProcessUser',
|
|
136
|
-
taskFunction: async (user: UserData): Promise<ProcessedUser> => {
|
|
137
|
-
return {
|
|
138
|
-
userId: user.id,
|
|
139
|
-
displayName: user.name.toUpperCase(),
|
|
140
|
-
normalized: true
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// Type safety enforced at compile time
|
|
146
|
-
const result: ProcessedUser = await processUserTask.trigger({
|
|
147
|
-
id: '123',
|
|
148
|
-
name: 'John Doe',
|
|
149
|
-
email: 'john@example.com'
|
|
94
|
+
const apiTask = new Task({
|
|
95
|
+
name: 'APIRequest',
|
|
96
|
+
taskFunction: async (endpoint) => {
|
|
97
|
+
return await fetch(endpoint).then(r => r.json());
|
|
98
|
+
},
|
|
99
|
+
buffered: true,
|
|
100
|
+
bufferMax: 5, // Maximum 5 concurrent executions
|
|
101
|
+
execDelay: 100 // Minimum 100ms between executions
|
|
150
102
|
});
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Generic Setup Values
|
|
154
103
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
interface TaskConfig {
|
|
159
|
-
apiEndpoint: string;
|
|
160
|
-
retryCount: number;
|
|
161
|
-
timeout: number;
|
|
104
|
+
// Rapid fire 100 calls - only 5 will execute concurrently
|
|
105
|
+
for (let i = 0; i < 100; i++) {
|
|
106
|
+
apiTask.trigger(`/api/data/${i}`);
|
|
162
107
|
}
|
|
163
|
-
|
|
164
|
-
const configuredTask = new Task<TaskConfig>({
|
|
165
|
-
name: 'ConfiguredTask',
|
|
166
|
-
taskSetup: async (): Promise<TaskConfig> => ({
|
|
167
|
-
apiEndpoint: 'https://api.example.com',
|
|
168
|
-
retryCount: 3,
|
|
169
|
-
timeout: 5000
|
|
170
|
-
}),
|
|
171
|
-
taskFunction: async (data: any, setupValue: TaskConfig) => {
|
|
172
|
-
// setupValue is fully typed!
|
|
173
|
-
for (let i = 0; i < setupValue.retryCount; i++) {
|
|
174
|
-
try {
|
|
175
|
-
return await fetchWithTimeout(
|
|
176
|
-
setupValue.apiEndpoint,
|
|
177
|
-
setupValue.timeout
|
|
178
|
-
);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
if (i === setupValue.retryCount - 1) throw error;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Type-Safe Task Chains
|
|
188
|
-
|
|
189
|
-
Chain tasks with preserved type flow:
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
// Each task knows its input and output types
|
|
193
|
-
const fetchTask = new Task<void>({
|
|
194
|
-
name: 'FetchUsers',
|
|
195
|
-
taskFunction: async (): Promise<UserData[]> => {
|
|
196
|
-
return await api.getUsers();
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const filterTask = new Task<void>({
|
|
201
|
-
name: 'FilterActive',
|
|
202
|
-
taskFunction: async (users: UserData[]): Promise<UserData[]> => {
|
|
203
|
-
return users.filter(user => user.isActive);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
const mapTask = new Task<void>({
|
|
208
|
-
name: 'MapToProcessed',
|
|
209
|
-
taskFunction: async (users: UserData[]): Promise<ProcessedUser[]> => {
|
|
210
|
-
return users.map(transformUser);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Type safety flows through the chain
|
|
215
|
-
const chain = new Taskchain({
|
|
216
|
-
name: 'UserPipeline',
|
|
217
|
-
taskArray: [fetchTask, filterTask, mapTask]
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const finalResult: ProcessedUser[] = await chain.trigger();
|
|
221
108
|
```
|
|
222
109
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
110
|
+
**Buffer Behavior:**
|
|
111
|
+
- First `bufferMax` calls execute immediately
|
|
112
|
+
- Additional calls are queued
|
|
113
|
+
- When buffer is full, new calls overwrite the last queued item
|
|
114
|
+
- Perfect for real-time data streams where only recent data matters
|
|
226
115
|
|
|
227
|
-
###
|
|
116
|
+
### Task Chains - Sequential Workflows
|
|
228
117
|
|
|
229
|
-
|
|
118
|
+
Build complex workflows with automatic data flow:
|
|
230
119
|
|
|
231
120
|
```typescript
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
{ name: 'schema', description: 'Updating schema', percentage: 30 },
|
|
237
|
-
{ name: 'data', description: 'Migrating data', percentage: 40 },
|
|
238
|
-
{ name: 'validate', description: 'Validating integrity', percentage: 10 }
|
|
239
|
-
] as const,
|
|
121
|
+
import { Task, Taskchain } from '@push.rocks/taskbuffer';
|
|
122
|
+
|
|
123
|
+
const fetchTask = new Task({
|
|
124
|
+
name: 'FetchData',
|
|
240
125
|
taskFunction: async () => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
console.log(`Progress: ${migrationTask.getProgress()}%`); // ~20%
|
|
244
|
-
|
|
245
|
-
migrationTask.notifyStep('schema');
|
|
246
|
-
await updateSchema();
|
|
247
|
-
console.log(`Progress: ${migrationTask.getProgress()}%`); // ~50%
|
|
248
|
-
|
|
249
|
-
migrationTask.notifyStep('data');
|
|
250
|
-
await migrateData();
|
|
251
|
-
console.log(`Progress: ${migrationTask.getProgress()}%`); // ~90%
|
|
252
|
-
|
|
253
|
-
migrationTask.notifyStep('validate');
|
|
254
|
-
await validateIntegrity();
|
|
255
|
-
console.log(`Progress: ${migrationTask.getProgress()}%`); // 100%
|
|
126
|
+
const response = await fetch('/api/data');
|
|
127
|
+
return response.json();
|
|
256
128
|
}
|
|
257
129
|
});
|
|
258
130
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
131
|
+
const transformTask = new Task({
|
|
132
|
+
name: 'TransformData',
|
|
133
|
+
taskFunction: async (data) => {
|
|
134
|
+
return data.map(item => ({
|
|
135
|
+
...item,
|
|
136
|
+
transformed: true,
|
|
137
|
+
timestamp: Date.now()
|
|
138
|
+
}));
|
|
265
139
|
}
|
|
266
140
|
});
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Task Metadata Collection
|
|
270
141
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
buffered: true,
|
|
277
|
-
bufferMax: 5,
|
|
278
|
-
steps: [
|
|
279
|
-
{ name: 'process', description: 'Processing', percentage: 100 }
|
|
280
|
-
] as const,
|
|
281
|
-
taskFunction: async () => {
|
|
282
|
-
task.notifyStep('process');
|
|
283
|
-
await processData();
|
|
142
|
+
const saveTask = new Task({
|
|
143
|
+
name: 'SaveData',
|
|
144
|
+
taskFunction: async (transformedData) => {
|
|
145
|
+
await database.save(transformedData);
|
|
146
|
+
return transformedData.length;
|
|
284
147
|
}
|
|
285
148
|
});
|
|
286
149
|
|
|
287
|
-
//
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
status: metadata.status, // 'idle' | 'running' | 'completed' | 'failed'
|
|
292
|
-
progress: metadata.currentProgress, // 0-100
|
|
293
|
-
currentStep: metadata.currentStep,
|
|
294
|
-
runCount: metadata.runCount,
|
|
295
|
-
lastRun: metadata.lastRun,
|
|
296
|
-
buffered: metadata.buffered,
|
|
297
|
-
bufferMax: metadata.bufferMax
|
|
150
|
+
// Create and execute chain
|
|
151
|
+
const dataChain = new Taskchain({
|
|
152
|
+
name: 'DataPipeline',
|
|
153
|
+
tasks: [fetchTask, transformTask, saveTask]
|
|
298
154
|
});
|
|
155
|
+
|
|
156
|
+
const savedCount = await dataChain.trigger();
|
|
157
|
+
console.log(`Saved ${savedCount} items`);
|
|
299
158
|
```
|
|
300
159
|
|
|
301
|
-
###
|
|
160
|
+
### Parallel Execution - Concurrent Processing
|
|
302
161
|
|
|
303
|
-
|
|
162
|
+
Execute multiple tasks simultaneously:
|
|
304
163
|
|
|
305
164
|
```typescript
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
// Add tasks with step tracking
|
|
309
|
-
manager.addAndScheduleTask(backupTask, '0 2 * * *'); // 2 AM daily
|
|
310
|
-
manager.addAndScheduleTask(cleanupTask, '0 */6 * * *'); // Every 6 hours
|
|
311
|
-
|
|
312
|
-
// Get metadata for all tasks
|
|
313
|
-
const allTasksMetadata = manager.getAllTasksMetadata();
|
|
314
|
-
allTasksMetadata.forEach(task => {
|
|
315
|
-
console.log(`Task: ${task.name}`);
|
|
316
|
-
console.log(` Status: ${task.status}`);
|
|
317
|
-
console.log(` Progress: ${task.currentProgress}%`);
|
|
318
|
-
console.log(` Run count: ${task.runCount}`);
|
|
319
|
-
console.log(` Schedule: ${task.cronSchedule}`);
|
|
320
|
-
});
|
|
165
|
+
import { TaskParallel } from '@push.rocks/taskbuffer';
|
|
321
166
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
167
|
+
const parallel = new TaskParallel({
|
|
168
|
+
name: 'ParallelProcessor',
|
|
169
|
+
tasks: [
|
|
170
|
+
emailTask,
|
|
171
|
+
smsTask,
|
|
172
|
+
pushNotificationTask,
|
|
173
|
+
webhookTask
|
|
174
|
+
]
|
|
329
175
|
});
|
|
330
176
|
|
|
331
|
-
//
|
|
332
|
-
const
|
|
333
|
-
|
|
177
|
+
// All tasks execute concurrently
|
|
178
|
+
const results = await parallel.trigger(notificationData);
|
|
179
|
+
// results = [emailResult, smsResult, pushResult, webhookResult]
|
|
334
180
|
```
|
|
335
181
|
|
|
336
|
-
###
|
|
182
|
+
### TaskManager - Centralized Orchestration
|
|
337
183
|
|
|
338
|
-
|
|
184
|
+
Manage all your tasks from a single point:
|
|
339
185
|
|
|
340
186
|
```typescript
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
187
|
+
const taskManager = new TaskManager();
|
|
188
|
+
|
|
189
|
+
// Add tasks
|
|
190
|
+
taskManager.addTask(dataProcessor);
|
|
191
|
+
taskManager.addTask(deploymentTask);
|
|
192
|
+
|
|
193
|
+
// Schedule tasks with cron
|
|
194
|
+
taskManager.addAndScheduleTask(backupTask, '0 2 * * *'); // Daily at 2 AM
|
|
195
|
+
taskManager.addAndScheduleTask(healthCheck, '*/5 * * * *'); // Every 5 minutes
|
|
196
|
+
|
|
197
|
+
// Get task metadata
|
|
198
|
+
const metadata = taskManager.getTaskMetadata('DeployApplication');
|
|
199
|
+
console.log(metadata);
|
|
200
|
+
// {
|
|
201
|
+
// name: 'DeployApplication',
|
|
202
|
+
// status: 'idle' | 'running' | 'completed' | 'failed',
|
|
203
|
+
// steps: [...],
|
|
204
|
+
// currentProgress: 75,
|
|
205
|
+
// runCount: 12,
|
|
206
|
+
// lastRun: Date,
|
|
207
|
+
// buffered: false,
|
|
208
|
+
// bufferMax: undefined,
|
|
209
|
+
// version: '1.0.0',
|
|
210
|
+
// timeout: 30000
|
|
211
|
+
// }
|
|
212
|
+
|
|
213
|
+
// Get all scheduled tasks
|
|
214
|
+
const scheduled = taskManager.getScheduledTasks();
|
|
215
|
+
scheduled.forEach(task => {
|
|
216
|
+
console.log(`${task.name}: Next run at ${task.nextRun}`);
|
|
360
217
|
});
|
|
361
218
|
|
|
362
|
-
// Execute
|
|
363
|
-
const report = await
|
|
219
|
+
// Execute and remove pattern
|
|
220
|
+
const report = await taskManager.addExecuteRemoveTask(temporaryTask, {
|
|
364
221
|
trackProgress: true
|
|
365
222
|
});
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
223
|
+
console.log(report);
|
|
224
|
+
// {
|
|
225
|
+
// taskName: 'TempTask',
|
|
226
|
+
// startTime: Date,
|
|
227
|
+
// endTime: Date,
|
|
228
|
+
// duration: 1523,
|
|
229
|
+
// steps: [...],
|
|
230
|
+
// stepsCompleted: ['step1', 'step2'],
|
|
231
|
+
// progress: 100,
|
|
232
|
+
// result: any,
|
|
233
|
+
// error?: Error
|
|
234
|
+
// }
|
|
374
235
|
```
|
|
375
236
|
|
|
376
|
-
|
|
237
|
+
## ๐จ Web Component Dashboard
|
|
377
238
|
|
|
378
|
-
|
|
239
|
+
Visualize your tasks in real-time with the included web component:
|
|
379
240
|
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
{ name: 'start', description: 'Starting...', percentage: 10 },
|
|
388
|
-
{ name: 'process', description: 'Processing...', percentage: 70 },
|
|
389
|
-
{ name: 'finish', description: 'Finishing...', percentage: 20 }
|
|
390
|
-
] as const,
|
|
391
|
-
taskFunction: async () => {
|
|
392
|
-
task.notifyStep('start');
|
|
393
|
-
socket.emit('progress', {
|
|
394
|
-
step: 'start',
|
|
395
|
-
progress: task.getProgress(),
|
|
396
|
-
metadata: task.getStepsMetadata()
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
task.notifyStep('process');
|
|
400
|
-
socket.emit('progress', {
|
|
401
|
-
step: 'process',
|
|
402
|
-
progress: task.getProgress(),
|
|
403
|
-
metadata: task.getStepsMetadata()
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
task.notifyStep('finish');
|
|
407
|
-
socket.emit('progress', {
|
|
408
|
-
step: 'finish',
|
|
409
|
-
progress: task.getProgress(),
|
|
410
|
-
metadata: task.getStepsMetadata()
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
});
|
|
241
|
+
```html
|
|
242
|
+
<!DOCTYPE html>
|
|
243
|
+
<html>
|
|
244
|
+
<head>
|
|
245
|
+
<script type="module">
|
|
246
|
+
import { TaskManager } from '@push.rocks/taskbuffer';
|
|
247
|
+
import '@push.rocks/taskbuffer/dist_ts_web/taskbuffer-dashboard.js';
|
|
414
248
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
When a task is buffered, TaskBuffer manages a queue of executions:
|
|
428
|
-
|
|
429
|
-
```typescript
|
|
430
|
-
const bufferedTask = new Task({
|
|
431
|
-
name: 'BufferedOperation',
|
|
432
|
-
taskFunction: async (data) => {
|
|
433
|
-
console.log(`Processing: ${data}`);
|
|
434
|
-
await simulateWork();
|
|
435
|
-
return `Processed: ${data}`;
|
|
436
|
-
},
|
|
437
|
-
buffered: true,
|
|
438
|
-
bufferMax: 3 // Maximum 3 concurrent executions
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
// Trigger 10 executions rapidly
|
|
442
|
-
for (let i = 0; i < 10; i++) {
|
|
443
|
-
bufferedTask.trigger(`Item ${i}`);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// What happens:
|
|
447
|
-
// 1. First 3 tasks start immediately
|
|
448
|
-
// 2. Items 4-10 are queued
|
|
449
|
-
// 3. As each task completes, next queued item starts
|
|
450
|
-
// 4. Never more than 3 tasks running simultaneously
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
### Buffer Truncation Behavior
|
|
454
|
-
|
|
455
|
-
When buffer limit is reached, new calls are intelligently managed:
|
|
456
|
-
|
|
457
|
-
```typescript
|
|
458
|
-
const truncatingTask = new Task({
|
|
459
|
-
name: 'TruncatingBuffer',
|
|
460
|
-
taskFunction: async (data) => {
|
|
461
|
-
await processData(data);
|
|
462
|
-
},
|
|
463
|
-
buffered: true,
|
|
464
|
-
bufferMax: 5 // Maximum 5 in buffer
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
// Rapid fire 100 calls
|
|
468
|
-
for (let i = 0; i < 100; i++) {
|
|
469
|
-
truncatingTask.trigger(`Data ${i}`);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// Buffer behavior:
|
|
473
|
-
// - First 5 calls: Added to buffer and start processing
|
|
474
|
-
// - Calls 6-100: Each overwrites the 5th buffer slot
|
|
475
|
-
// - Result: Only processes items 0,1,2,3, and 99 (last one)
|
|
476
|
-
// - This prevents memory overflow in high-frequency scenarios
|
|
249
|
+
const taskManager = new TaskManager();
|
|
250
|
+
|
|
251
|
+
// Attach to dashboard
|
|
252
|
+
const dashboard = document.querySelector('taskbuffer-dashboard');
|
|
253
|
+
dashboard.taskManager = taskManager;
|
|
254
|
+
dashboard.refreshInterval = 500; // Update every 500ms
|
|
255
|
+
</script>
|
|
256
|
+
</head>
|
|
257
|
+
<body>
|
|
258
|
+
<taskbuffer-dashboard></taskbuffer-dashboard>
|
|
259
|
+
</body>
|
|
260
|
+
</html>
|
|
477
261
|
```
|
|
478
262
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
263
|
+
The dashboard provides:
|
|
264
|
+
- ๐ Real-time progress bars with step indicators
|
|
265
|
+
- ๐ Task execution history
|
|
266
|
+
- โฐ Scheduled task information
|
|
267
|
+
- ๐ฏ Interactive task controls
|
|
268
|
+
- ๐ Light/dark theme support
|
|
483
269
|
|
|
484
|
-
|
|
485
|
-
const slidingWindowTask = new Task({
|
|
486
|
-
name: 'SlidingWindow',
|
|
487
|
-
taskFunction: async (data) => {
|
|
488
|
-
return await analyzeRecentData(data);
|
|
489
|
-
},
|
|
490
|
-
buffered: true,
|
|
491
|
-
bufferMax: 10, // Keep last 10 items
|
|
492
|
-
execDelay: 100 // Process every 100ms
|
|
493
|
-
});
|
|
270
|
+
## ๐งฉ Advanced Patterns
|
|
494
271
|
|
|
495
|
-
|
|
496
|
-
dataStream.on('data', (chunk) => {
|
|
497
|
-
slidingWindowTask.trigger(chunk);
|
|
498
|
-
// Older items automatically dropped when buffer full
|
|
499
|
-
});
|
|
500
|
-
```
|
|
272
|
+
### Dynamic Task Routing
|
|
501
273
|
|
|
502
|
-
|
|
503
|
-
Combine buffering with execution delays for rate limiting:
|
|
274
|
+
Route tasks based on conditions:
|
|
504
275
|
|
|
505
276
|
```typescript
|
|
506
|
-
const
|
|
507
|
-
name: '
|
|
277
|
+
const routerTask = new Task({
|
|
278
|
+
name: 'Router',
|
|
508
279
|
taskFunction: async (request) => {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
280
|
+
if (request.priority === 'high') {
|
|
281
|
+
return await expressProcessor.trigger(request);
|
|
282
|
+
} else if (request.size > 1000000) {
|
|
283
|
+
return await bulkProcessor.trigger(request);
|
|
284
|
+
} else {
|
|
285
|
+
return await standardProcessor.trigger(request);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
514
288
|
});
|
|
515
|
-
|
|
516
|
-
// Requests are queued and executed at 1/second
|
|
517
|
-
// Prevents API rate limit violations
|
|
518
289
|
```
|
|
519
290
|
|
|
520
|
-
|
|
521
|
-
|
|
291
|
+
### Task Pools
|
|
292
|
+
|
|
293
|
+
Create reusable task pools for load distribution:
|
|
522
294
|
|
|
523
295
|
```typescript
|
|
524
|
-
class
|
|
525
|
-
private
|
|
296
|
+
class TaskPool {
|
|
297
|
+
private tasks: Task[] = [];
|
|
298
|
+
private currentIndex = 0;
|
|
526
299
|
|
|
527
|
-
constructor(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
});
|
|
300
|
+
constructor(poolSize: number, taskConfig: any) {
|
|
301
|
+
for (let i = 0; i < poolSize; i++) {
|
|
302
|
+
this.tasks.push(new Task({
|
|
303
|
+
...taskConfig,
|
|
304
|
+
name: `${taskConfig.name}_${i}`
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
535
307
|
}
|
|
536
308
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
this.priorityQueue.pop();
|
|
542
|
-
}
|
|
543
|
-
this.priorityQueue.push({data, priority});
|
|
544
|
-
this.priorityQueue.sort((a, b) => b.priority - a.priority);
|
|
545
|
-
return this.trigger(this.priorityQueue.shift());
|
|
309
|
+
async execute(data: any) {
|
|
310
|
+
const task = this.tasks[this.currentIndex];
|
|
311
|
+
this.currentIndex = (this.currentIndex + 1) % this.tasks.length;
|
|
312
|
+
return await task.trigger(data);
|
|
546
313
|
}
|
|
547
314
|
}
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
### Buffer Monitoring
|
|
551
|
-
|
|
552
|
-
Track buffer utilization and performance:
|
|
553
|
-
|
|
554
|
-
```typescript
|
|
555
|
-
const monitoredTask = new Task({
|
|
556
|
-
name: 'MonitoredBuffer',
|
|
557
|
-
taskFunction: async (data) => {
|
|
558
|
-
const startTime = Date.now();
|
|
559
|
-
const result = await processData(data);
|
|
560
|
-
console.log(`Processing time: ${Date.now() - startTime}ms`);
|
|
561
|
-
console.log(`Buffer utilization: ${monitoredTask.bufferRunner.bufferCounter}/${monitoredTask.bufferMax}`);
|
|
562
|
-
return result;
|
|
563
|
-
},
|
|
564
|
-
buffered: true,
|
|
565
|
-
bufferMax: 20
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
// Monitor buffer saturation
|
|
569
|
-
setInterval(() => {
|
|
570
|
-
const utilization = (monitoredTask.bufferRunner.bufferCounter / monitoredTask.bufferMax) * 100;
|
|
571
|
-
if (utilization > 80) {
|
|
572
|
-
console.warn(`Buffer near capacity: ${utilization.toFixed(1)}%`);
|
|
573
|
-
}
|
|
574
|
-
}, 1000);
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
### Buffer Best Practices
|
|
578
|
-
|
|
579
|
-
1. **Choose appropriate buffer sizes**:
|
|
580
|
-
- I/O operations: 5-10 concurrent
|
|
581
|
-
- CPU-intensive: Number of cores
|
|
582
|
-
- API calls: Based on rate limits
|
|
583
|
-
|
|
584
|
-
2. **Handle buffer overflow gracefully**:
|
|
585
|
-
```typescript
|
|
586
|
-
const task = new Task({
|
|
587
|
-
taskFunction: async (data) => {
|
|
588
|
-
try {
|
|
589
|
-
return await process(data);
|
|
590
|
-
} catch (error) {
|
|
591
|
-
if (error.code === 'BUFFER_OVERFLOW') {
|
|
592
|
-
// Implement backoff strategy
|
|
593
|
-
await delay(1000);
|
|
594
|
-
return task.trigger(data);
|
|
595
|
-
}
|
|
596
|
-
throw error;
|
|
597
|
-
}
|
|
598
|
-
},
|
|
599
|
-
buffered: true,
|
|
600
|
-
bufferMax: 10
|
|
601
|
-
});
|
|
602
|
-
```
|
|
603
|
-
|
|
604
|
-
3. **Monitor and adjust dynamically**:
|
|
605
|
-
```typescript
|
|
606
|
-
// Adjust buffer size based on system load
|
|
607
|
-
const adaptiveTask = new Task({
|
|
608
|
-
name: 'AdaptiveBuffer',
|
|
609
|
-
taskFunction: async (data) => {
|
|
610
|
-
const cpuLoad = await getSystemLoad();
|
|
611
|
-
if (cpuLoad > 0.8) {
|
|
612
|
-
adaptiveTask.bufferMax = Math.max(2, adaptiveTask.bufferMax - 1);
|
|
613
|
-
} else if (cpuLoad < 0.5) {
|
|
614
|
-
adaptiveTask.bufferMax = Math.min(20, adaptiveTask.bufferMax + 1);
|
|
615
|
-
}
|
|
616
|
-
return await process(data);
|
|
617
|
-
},
|
|
618
|
-
buffered: true,
|
|
619
|
-
bufferMax: 10
|
|
620
|
-
});
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
## Common Patterns ๐จ
|
|
624
|
-
|
|
625
|
-
### Task Chains - Sequential Workflows
|
|
626
|
-
|
|
627
|
-
Build complex workflows where each step depends on the previous:
|
|
628
|
-
|
|
629
|
-
```typescript
|
|
630
|
-
import { Task, Taskchain } from '@push.rocks/taskbuffer';
|
|
631
315
|
|
|
632
|
-
const
|
|
633
|
-
name: '
|
|
634
|
-
taskFunction: async () =>
|
|
635
|
-
const response = await fetch('/api/data');
|
|
636
|
-
return response.json();
|
|
637
|
-
},
|
|
638
|
-
});
|
|
639
|
-
|
|
640
|
-
const transformTask = new Task({
|
|
641
|
-
name: 'TransformData',
|
|
642
|
-
taskFunction: async (data) => {
|
|
643
|
-
return data.map((item) => ({
|
|
644
|
-
...item,
|
|
645
|
-
processed: true,
|
|
646
|
-
timestamp: Date.now(),
|
|
647
|
-
}));
|
|
648
|
-
},
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
const saveTask = new Task({
|
|
652
|
-
name: 'SaveData',
|
|
653
|
-
taskFunction: async (transformedData) => {
|
|
654
|
-
await database.bulkInsert(transformedData);
|
|
655
|
-
return { saved: transformedData.length };
|
|
656
|
-
},
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
const workflow = new Taskchain({
|
|
660
|
-
name: 'DataPipeline',
|
|
661
|
-
taskArray: [fetchTask, transformTask, saveTask],
|
|
316
|
+
const processorPool = new TaskPool(5, {
|
|
317
|
+
name: 'DataProcessor',
|
|
318
|
+
taskFunction: async (data) => processData(data)
|
|
662
319
|
});
|
|
663
|
-
|
|
664
|
-
// Execute the entire chain
|
|
665
|
-
const result = await workflow.trigger();
|
|
666
|
-
console.log(`Processed ${result.saved} items`);
|
|
667
320
|
```
|
|
668
321
|
|
|
669
|
-
###
|
|
322
|
+
### Error Recovery & Retry
|
|
670
323
|
|
|
671
|
-
|
|
324
|
+
Implement robust error handling:
|
|
672
325
|
|
|
673
326
|
```typescript
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
taskArray: tasks,
|
|
327
|
+
const resilientTask = new Task({
|
|
328
|
+
name: 'ResilientTask',
|
|
329
|
+
taskFunction: async (data, retryCount = 0) => {
|
|
330
|
+
try {
|
|
331
|
+
return await riskyOperation(data);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
if (retryCount < 3) {
|
|
334
|
+
console.log(`Retry ${retryCount + 1}/3`);
|
|
335
|
+
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, retryCount)));
|
|
336
|
+
return await resilientTask.trigger(data, retryCount + 1);
|
|
337
|
+
}
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
689
341
|
});
|
|
690
|
-
|
|
691
|
-
// All tasks execute simultaneously
|
|
692
|
-
const [users, posts, comments] = await parallelFetch.trigger();
|
|
693
342
|
```
|
|
694
343
|
|
|
695
|
-
###
|
|
344
|
+
### Task Composition
|
|
696
345
|
|
|
697
|
-
|
|
346
|
+
Compose complex behaviors from simple tasks:
|
|
698
347
|
|
|
699
348
|
```typescript
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
const backupTask = new Task({
|
|
703
|
-
name: 'DatabaseBackup',
|
|
349
|
+
const compositeTask = new Task({
|
|
350
|
+
name: 'CompositeOperation',
|
|
704
351
|
steps: [
|
|
705
|
-
{ name: '
|
|
706
|
-
{ name: '
|
|
352
|
+
{ name: 'validate', description: 'Validating input', percentage: 20 },
|
|
353
|
+
{ name: 'process', description: 'Processing data', percentage: 60 },
|
|
354
|
+
{ name: 'notify', description: 'Sending notifications', percentage: 20 }
|
|
707
355
|
] as const,
|
|
708
|
-
taskFunction: async ()
|
|
709
|
-
|
|
710
|
-
await
|
|
356
|
+
taskFunction: async function(data) {
|
|
357
|
+
this.notifyStep('validate');
|
|
358
|
+
const validated = await validationTask.trigger(data);
|
|
711
359
|
|
|
712
|
-
|
|
713
|
-
await
|
|
360
|
+
this.notifyStep('process');
|
|
361
|
+
const processed = await processingTask.trigger(validated);
|
|
714
362
|
|
|
715
|
-
|
|
716
|
-
|
|
363
|
+
this.notifyStep('notify');
|
|
364
|
+
await notificationTask.trigger(processed);
|
|
365
|
+
|
|
366
|
+
return processed;
|
|
367
|
+
}
|
|
717
368
|
});
|
|
718
|
-
|
|
719
|
-
const manager = new TaskManager();
|
|
720
|
-
|
|
721
|
-
// Add and schedule tasks
|
|
722
|
-
manager.addAndScheduleTask(backupTask, '0 0 * * *'); // Daily at midnight
|
|
723
|
-
|
|
724
|
-
// Start the scheduler
|
|
725
|
-
manager.start();
|
|
726
|
-
|
|
727
|
-
// Monitor scheduled tasks
|
|
728
|
-
const scheduled = manager.getScheduledTasks();
|
|
729
|
-
console.log('Scheduled tasks:', scheduled);
|
|
730
|
-
|
|
731
|
-
// Later... stop if needed
|
|
732
|
-
manager.stop();
|
|
733
369
|
```
|
|
734
370
|
|
|
735
|
-
|
|
371
|
+
## ๐ง Configuration
|
|
736
372
|
|
|
737
|
-
|
|
373
|
+
### Task Options
|
|
738
374
|
|
|
739
375
|
```typescript
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
saveTask.trigger(e.target.value);
|
|
754
|
-
});
|
|
376
|
+
interface TaskOptions<T = undefined, TSteps = []> {
|
|
377
|
+
name?: string; // Task identifier
|
|
378
|
+
taskFunction: Function; // Async function to execute
|
|
379
|
+
buffered?: boolean; // Enable buffering
|
|
380
|
+
bufferMax?: number; // Max concurrent executions
|
|
381
|
+
execDelay?: number; // Min delay between executions
|
|
382
|
+
timeout?: number; // Task timeout in ms
|
|
383
|
+
version?: string; // Task version
|
|
384
|
+
steps?: TSteps; // Progress steps configuration
|
|
385
|
+
taskSetup?: Function; // One-time setup function
|
|
386
|
+
beforeTask?: Function; // Runs before each execution
|
|
387
|
+
afterTask?: Function; // Runs after each execution
|
|
388
|
+
}
|
|
755
389
|
```
|
|
756
390
|
|
|
757
|
-
###
|
|
758
|
-
|
|
759
|
-
Ensure initialization code runs exactly once:
|
|
391
|
+
### TaskManager Options
|
|
760
392
|
|
|
761
393
|
```typescript
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
taskFunction: async () => {
|
|
767
|
-
await database.connect();
|
|
768
|
-
await cache.initialize();
|
|
769
|
-
await loadConfiguration();
|
|
770
|
-
console.log('System initialized');
|
|
771
|
-
},
|
|
394
|
+
const taskManager = new TaskManager({
|
|
395
|
+
maxConcurrentTasks: 10, // Global concurrency limit
|
|
396
|
+
defaultTimeout: 30000, // Default task timeout
|
|
397
|
+
logLevel: 'info' // Logging verbosity
|
|
772
398
|
});
|
|
773
|
-
|
|
774
|
-
// Safe to call multiple times - only runs once
|
|
775
|
-
await initTask.trigger();
|
|
776
|
-
await initTask.trigger(); // This won't run again
|
|
777
399
|
```
|
|
778
400
|
|
|
779
|
-
##
|
|
780
|
-
|
|
781
|
-
### Task Dependencies with Pre/Post Hooks
|
|
401
|
+
## ๐ Monitoring & Observability
|
|
782
402
|
|
|
783
|
-
|
|
403
|
+
### Task Events
|
|
784
404
|
|
|
785
405
|
```typescript
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
throw new Error('Validation failed');
|
|
791
|
-
}
|
|
792
|
-
return data;
|
|
793
|
-
},
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
const mainTask = new Task({
|
|
797
|
-
name: 'ProcessData',
|
|
798
|
-
taskFunction: async (data) => {
|
|
799
|
-
return await complexProcessing(data);
|
|
800
|
-
},
|
|
801
|
-
preTask: validationTask, // Runs before main task
|
|
802
|
-
afterTask: cleanupTask, // Runs after main task
|
|
803
|
-
});
|
|
406
|
+
task.on('started', () => console.log('Task started'));
|
|
407
|
+
task.on('completed', (result) => console.log('Task completed:', result));
|
|
408
|
+
task.on('failed', (error) => console.error('Task failed:', error));
|
|
409
|
+
task.on('stepChange', (step) => console.log('Step:', step.name));
|
|
804
410
|
```
|
|
805
411
|
|
|
806
|
-
###
|
|
807
|
-
|
|
808
|
-
The TaskRunner system enables distributed task execution across multiple workers:
|
|
412
|
+
### Execution Metrics
|
|
809
413
|
|
|
810
414
|
```typescript
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
415
|
+
const metrics = task.getMetrics();
|
|
416
|
+
console.log({
|
|
417
|
+
totalRuns: metrics.runCount,
|
|
418
|
+
averageDuration: metrics.avgDuration,
|
|
419
|
+
successRate: metrics.successRate,
|
|
420
|
+
lastError: metrics.lastError
|
|
816
421
|
});
|
|
817
|
-
|
|
818
|
-
// Register tasks this runner can handle
|
|
819
|
-
runner.registerTask(dataProcessingTask);
|
|
820
|
-
runner.registerTask(imageResizeTask);
|
|
821
|
-
|
|
822
|
-
// Start processing
|
|
823
|
-
runner.start();
|
|
824
|
-
```
|
|
825
|
-
|
|
826
|
-
### Dynamic Task Creation
|
|
827
|
-
|
|
828
|
-
Create tasks on-the-fly based on runtime conditions:
|
|
829
|
-
|
|
830
|
-
```typescript
|
|
831
|
-
const dynamicWorkflow = async (config: Config) => {
|
|
832
|
-
const tasks = config.steps.map(
|
|
833
|
-
(step) =>
|
|
834
|
-
new Task({
|
|
835
|
-
name: step.name,
|
|
836
|
-
steps: step.substeps?.map(s => ({
|
|
837
|
-
name: s.id,
|
|
838
|
-
description: s.label,
|
|
839
|
-
percentage: s.weight
|
|
840
|
-
})) as const,
|
|
841
|
-
taskFunction: async (input) => {
|
|
842
|
-
for (const substep of step.substeps || []) {
|
|
843
|
-
task.notifyStep(substep.id);
|
|
844
|
-
await processStep(substep, input);
|
|
845
|
-
}
|
|
846
|
-
return input;
|
|
847
|
-
},
|
|
848
|
-
}),
|
|
849
|
-
);
|
|
850
|
-
|
|
851
|
-
const chain = new Taskchain({
|
|
852
|
-
name: 'DynamicWorkflow',
|
|
853
|
-
taskArray: tasks,
|
|
854
|
-
});
|
|
855
|
-
|
|
856
|
-
return await chain.trigger();
|
|
857
|
-
};
|
|
858
422
|
```
|
|
859
423
|
|
|
860
|
-
##
|
|
861
|
-
|
|
862
|
-
### Task Options
|
|
863
|
-
|
|
864
|
-
| Option | Type | Description |
|
|
865
|
-
| -------------- | ---------- | -------------------------------------- |
|
|
866
|
-
| `name` | `string` | Unique identifier for the task |
|
|
867
|
-
| `taskFunction` | `Function` | Async function to execute |
|
|
868
|
-
| `steps` | `Array` | Step definitions with name, description, percentage |
|
|
869
|
-
| `buffered` | `boolean` | Enable buffer management |
|
|
870
|
-
| `bufferMax` | `number` | Maximum concurrent executions |
|
|
871
|
-
| `execDelay` | `number` | Delay between executions (ms) |
|
|
872
|
-
| `timeout` | `number` | Task timeout (ms) |
|
|
873
|
-
| `preTask` | `Task` | Task to run before |
|
|
874
|
-
| `afterTask` | `Task` | Task to run after |
|
|
875
|
-
|
|
876
|
-
### Task Methods
|
|
877
|
-
|
|
878
|
-
| Method | Description |
|
|
879
|
-
| ------------------------- | ---------------------------------------------- |
|
|
880
|
-
| `trigger(x?)` | Execute the task |
|
|
881
|
-
| `notifyStep(stepName)` | Mark a step as active (typed step names!) |
|
|
882
|
-
| `getProgress()` | Get current progress percentage (0-100) |
|
|
883
|
-
| `getStepsMetadata()` | Get all steps with their current status |
|
|
884
|
-
| `getMetadata()` | Get complete task metadata |
|
|
885
|
-
| `resetSteps()` | Reset all steps to pending state |
|
|
886
|
-
|
|
887
|
-
### TaskManager Methods
|
|
888
|
-
|
|
889
|
-
| Method | Description |
|
|
890
|
-
| ----------------------------------- | -------------------------------------- |
|
|
891
|
-
| `addTask(task)` | Add a task to the manager |
|
|
892
|
-
| `addAndScheduleTask(task, cron)` | Add and schedule a task |
|
|
893
|
-
| `getTaskByName(name)` | Get a specific task by name |
|
|
894
|
-
| `getTaskMetadata(name)` | Get metadata for a specific task |
|
|
895
|
-
| `getAllTasksMetadata()` | Get metadata for all tasks |
|
|
896
|
-
| `getScheduledTasks()` | Get all scheduled tasks with info |
|
|
897
|
-
| `getNextScheduledRuns(limit)` | Get upcoming scheduled executions |
|
|
898
|
-
| `addExecuteRemoveTask(task, opts)` | Execute task with lifecycle tracking |
|
|
899
|
-
| `triggerTaskByName(name)` | Trigger a task by its name |
|
|
900
|
-
| `scheduleTaskByName(name, cron)` | Schedule a task using cron expression |
|
|
901
|
-
| `descheduleTaskByName(name)` | Remove task from schedule |
|
|
902
|
-
| `start()` | Start the scheduler |
|
|
903
|
-
| `stop()` | Stop the scheduler |
|
|
904
|
-
|
|
905
|
-
### Taskchain Methods
|
|
906
|
-
|
|
907
|
-
| Method | Description |
|
|
908
|
-
| ----------------------- | ---------------------- |
|
|
909
|
-
| `addTask(task)` | Add task to chain |
|
|
910
|
-
| `removeTask(taskName)` | Remove task from chain |
|
|
911
|
-
| `trigger(initialValue)` | Execute the chain |
|
|
912
|
-
| `reset()` | Reset chain state |
|
|
913
|
-
|
|
914
|
-
## Performance Tips ๐๏ธ
|
|
915
|
-
|
|
916
|
-
1. **Use buffering for I/O operations**: Prevents overwhelming external services
|
|
917
|
-
2. **Leverage parallel execution**: When tasks are independent, run them simultaneously
|
|
918
|
-
3. **Implement proper error handling**: Use try-catch in task functions
|
|
919
|
-
4. **Monitor task execution**: Use the built-in stats and logging
|
|
920
|
-
5. **Set appropriate timeouts**: Prevent hanging tasks from blocking your system
|
|
921
|
-
6. **Use step tracking wisely**: Don't create too many granular steps - aim for meaningful progress points
|
|
922
|
-
|
|
923
|
-
## Error Handling ๐ก๏ธ
|
|
424
|
+
## ๐งช Testing
|
|
924
425
|
|
|
925
426
|
```typescript
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
steps: [
|
|
929
|
-
{ name: 'try', description: 'Attempting operation', percentage: 80 },
|
|
930
|
-
{ name: 'retry', description: 'Retrying on failure', percentage: 20 }
|
|
931
|
-
] as const,
|
|
932
|
-
taskFunction: async (input) => {
|
|
933
|
-
try {
|
|
934
|
-
robustTask.notifyStep('try');
|
|
935
|
-
return await riskyOperation(input);
|
|
936
|
-
} catch (error) {
|
|
937
|
-
// Log error
|
|
938
|
-
console.error(`Task failed: ${error.message}`);
|
|
939
|
-
|
|
940
|
-
// Optionally retry
|
|
941
|
-
if (error.retryable) {
|
|
942
|
-
robustTask.notifyStep('retry');
|
|
943
|
-
return await riskyOperation(input);
|
|
944
|
-
}
|
|
427
|
+
import { expect, tap } from '@git.zone/tstest';
|
|
428
|
+
import { Task } from '@push.rocks/taskbuffer';
|
|
945
429
|
|
|
946
|
-
|
|
947
|
-
|
|
430
|
+
tap.test('Task should execute with progress tracking', async () => {
|
|
431
|
+
const task = new Task({
|
|
432
|
+
name: 'TestTask',
|
|
433
|
+
steps: [
|
|
434
|
+
{ name: 'step1', description: 'Step 1', percentage: 50 },
|
|
435
|
+
{ name: 'step2', description: 'Step 2', percentage: 50 }
|
|
436
|
+
] as const,
|
|
437
|
+
taskFunction: async function() {
|
|
438
|
+
this.notifyStep('step1');
|
|
439
|
+
await new Promise(r => setTimeout(r, 100));
|
|
440
|
+
this.notifyStep('step2');
|
|
441
|
+
return 'done';
|
|
948
442
|
}
|
|
949
|
-
}
|
|
950
|
-
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const result = await task.trigger();
|
|
446
|
+
expect(result).toEqual('done');
|
|
447
|
+
expect(task.getProgress()).toEqual(100);
|
|
951
448
|
});
|
|
952
449
|
```
|
|
953
450
|
|
|
954
|
-
## Real-World Examples
|
|
451
|
+
## ๐ Real-World Examples
|
|
955
452
|
|
|
956
|
-
### API Rate
|
|
453
|
+
### API Rate Limiter
|
|
957
454
|
|
|
958
455
|
```typescript
|
|
959
|
-
const
|
|
960
|
-
name: '
|
|
961
|
-
steps: [
|
|
962
|
-
{ name: 'wait', description: 'Rate limit delay', percentage: 10 },
|
|
963
|
-
{ name: 'call', description: 'API call', percentage: 90 }
|
|
964
|
-
] as const,
|
|
965
|
-
taskFunction: async (endpoint: string) => {
|
|
966
|
-
apiClient.notifyStep('wait');
|
|
967
|
-
await delay(100); // Rate limiting
|
|
968
|
-
|
|
969
|
-
apiClient.notifyStep('call');
|
|
970
|
-
return await fetch(`https://api.example.com${endpoint}`);
|
|
971
|
-
},
|
|
456
|
+
const apiLimiter = new Task({
|
|
457
|
+
name: 'APIRateLimiter',
|
|
972
458
|
buffered: true,
|
|
973
|
-
bufferMax: 10,
|
|
974
|
-
execDelay: 100, //
|
|
459
|
+
bufferMax: 10, // Max 10 requests per second
|
|
460
|
+
execDelay: 100, // 100ms between requests
|
|
461
|
+
taskFunction: async (endpoint, data) => {
|
|
462
|
+
return await fetch(endpoint, {
|
|
463
|
+
method: 'POST',
|
|
464
|
+
body: JSON.stringify(data)
|
|
465
|
+
});
|
|
466
|
+
}
|
|
975
467
|
});
|
|
976
468
|
```
|
|
977
469
|
|
|
978
|
-
### Database Migration Pipeline
|
|
470
|
+
### Database Migration Pipeline
|
|
979
471
|
|
|
980
472
|
```typescript
|
|
981
473
|
const migrationChain = new Taskchain({
|
|
982
474
|
name: 'DatabaseMigration',
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
const changes = await analyzeSchema();
|
|
1001
|
-
|
|
1002
|
-
schemaTask.notifyStep('apply');
|
|
1003
|
-
return await applyMigrations(changes);
|
|
1004
|
-
}
|
|
1005
|
-
}),
|
|
1006
|
-
// ... more tasks
|
|
1007
|
-
],
|
|
1008
|
-
});
|
|
1009
|
-
|
|
1010
|
-
// Execute with progress monitoring
|
|
1011
|
-
const result = await migrationChain.trigger();
|
|
475
|
+
tasks: [
|
|
476
|
+
backupDatabaseTask,
|
|
477
|
+
validateSchemaTask,
|
|
478
|
+
runMigrationsTask,
|
|
479
|
+
verifyIntegrityTask,
|
|
480
|
+
updateIndexesTask
|
|
481
|
+
]
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// Execute with rollback on failure
|
|
485
|
+
try {
|
|
486
|
+
await migrationChain.trigger();
|
|
487
|
+
console.log('Migration successful!');
|
|
488
|
+
} catch (error) {
|
|
489
|
+
await rollbackTask.trigger();
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
1012
492
|
```
|
|
1013
493
|
|
|
1014
|
-
###
|
|
494
|
+
### Distributed Job Queue
|
|
1015
495
|
|
|
1016
496
|
```typescript
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1019
|
-
services.forEach((service) => {
|
|
1020
|
-
const healthCheck = new Task({
|
|
1021
|
-
name: `HealthCheck:${service.name}`,
|
|
1022
|
-
steps: [
|
|
1023
|
-
{ name: 'ping', description: 'Pinging service', percentage: 30 },
|
|
1024
|
-
{ name: 'check', description: 'Checking health', percentage: 50 },
|
|
1025
|
-
{ name: 'report', description: 'Reporting status', percentage: 20 }
|
|
1026
|
-
] as const,
|
|
1027
|
-
taskFunction: async () => {
|
|
1028
|
-
healthCheck.notifyStep('ping');
|
|
1029
|
-
const responsive = await ping(service.url);
|
|
1030
|
-
|
|
1031
|
-
healthCheck.notifyStep('check');
|
|
1032
|
-
const healthy = await checkHealth(service.url);
|
|
1033
|
-
|
|
1034
|
-
healthCheck.notifyStep('report');
|
|
1035
|
-
if (!healthy) {
|
|
1036
|
-
await alertOps(service);
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
return { service: service.name, healthy, timestamp: Date.now() };
|
|
1040
|
-
},
|
|
1041
|
-
});
|
|
497
|
+
const jobQueue = new TaskManager();
|
|
1042
498
|
|
|
1043
|
-
|
|
499
|
+
// Worker tasks
|
|
500
|
+
const imageProcessor = new Task({
|
|
501
|
+
name: 'ImageProcessor',
|
|
502
|
+
buffered: true,
|
|
503
|
+
bufferMax: 5,
|
|
504
|
+
steps: [
|
|
505
|
+
{ name: 'download', description: 'Downloading', percentage: 20 },
|
|
506
|
+
{ name: 'resize', description: 'Resizing', percentage: 40 },
|
|
507
|
+
{ name: 'optimize', description: 'Optimizing', percentage: 30 },
|
|
508
|
+
{ name: 'upload', description: 'Uploading', percentage: 10 }
|
|
509
|
+
] as const,
|
|
510
|
+
taskFunction: async function(job) {
|
|
511
|
+
this.notifyStep('download');
|
|
512
|
+
const image = await downloadImage(job.url);
|
|
513
|
+
|
|
514
|
+
this.notifyStep('resize');
|
|
515
|
+
const resized = await resizeImage(image, job.dimensions);
|
|
516
|
+
|
|
517
|
+
this.notifyStep('optimize');
|
|
518
|
+
const optimized = await optimizeImage(resized);
|
|
519
|
+
|
|
520
|
+
this.notifyStep('upload');
|
|
521
|
+
return await uploadToCDN(optimized);
|
|
522
|
+
}
|
|
1044
523
|
});
|
|
1045
524
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
status: task.status,
|
|
1053
|
-
lastCheck: task.lastRun,
|
|
1054
|
-
nextCheck: healthMonitor.getScheduledTasks()
|
|
1055
|
-
.find(s => s.name === task.name)?.nextRun,
|
|
1056
|
-
progress: task.currentProgress,
|
|
1057
|
-
currentStep: task.currentStep
|
|
1058
|
-
}))
|
|
1059
|
-
});
|
|
525
|
+
jobQueue.addTask(imageProcessor);
|
|
526
|
+
|
|
527
|
+
// Process incoming jobs
|
|
528
|
+
messageQueue.on('job', async (job) => {
|
|
529
|
+
const result = await jobQueue.getTaskByName('ImageProcessor').trigger(job);
|
|
530
|
+
await messageQueue.ack(job.id, result);
|
|
1060
531
|
});
|
|
1061
532
|
```
|
|
1062
533
|
|
|
1063
|
-
##
|
|
534
|
+
## ๐ Performance Tips
|
|
1064
535
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
536
|
+
1. **Use Buffering Wisely** - Enable buffering for I/O-bound tasks
|
|
537
|
+
2. **Set Appropriate Delays** - Use `execDelay` to prevent API rate limits
|
|
538
|
+
3. **Leverage Task Pools** - Distribute load across multiple task instances
|
|
539
|
+
4. **Monitor Progress** - Use step tracking for long-running operations
|
|
540
|
+
5. **Clean Up** - Use `addExecuteRemoveTask` for one-time operations
|
|
1068
541
|
|
|
1069
|
-
|
|
1070
|
-
const task = new Task({
|
|
1071
|
-
name: 'TestTask',
|
|
1072
|
-
steps: [
|
|
1073
|
-
{ name: 'step1', description: 'First step', percentage: 50 },
|
|
1074
|
-
{ name: 'step2', description: 'Second step', percentage: 50 }
|
|
1075
|
-
] as const,
|
|
1076
|
-
taskFunction: async () => {
|
|
1077
|
-
task.notifyStep('step1');
|
|
1078
|
-
expect(task.getProgress()).toBeLessThanOrEqual(50);
|
|
1079
|
-
|
|
1080
|
-
task.notifyStep('step2');
|
|
1081
|
-
expect(task.getProgress()).toBeLessThanOrEqual(100);
|
|
1082
|
-
}
|
|
1083
|
-
});
|
|
1084
|
-
|
|
1085
|
-
await task.trigger();
|
|
1086
|
-
expect(task.getProgress()).toEqual(100);
|
|
1087
|
-
});
|
|
542
|
+
## ๐ Debugging
|
|
1088
543
|
|
|
1089
|
-
|
|
1090
|
-
const manager = new TaskManager();
|
|
1091
|
-
const task = new Task({
|
|
1092
|
-
name: 'MetadataTest',
|
|
1093
|
-
taskFunction: async () => 'result'
|
|
1094
|
-
});
|
|
1095
|
-
|
|
1096
|
-
const report = await manager.addExecuteRemoveTask(task);
|
|
1097
|
-
expect(report.taskName).toEqual('MetadataTest');
|
|
1098
|
-
expect(report.result).toEqual('result');
|
|
1099
|
-
expect(report.duration).toBeGreaterThan(0);
|
|
1100
|
-
});
|
|
544
|
+
Enable detailed logging:
|
|
1101
545
|
|
|
1102
|
-
|
|
1103
|
-
|
|
546
|
+
```typescript
|
|
547
|
+
import { logger } from '@push.rocks/smartlog';
|
|
1104
548
|
|
|
1105
|
-
|
|
549
|
+
logger.enableConsole();
|
|
550
|
+
logger.level = 'debug';
|
|
551
|
+
|
|
552
|
+
// Tasks will now output detailed execution logs
|
|
553
|
+
```
|
|
1106
554
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
555
|
+
## ๐ API Reference
|
|
556
|
+
|
|
557
|
+
### Core Classes
|
|
558
|
+
|
|
559
|
+
- **`Task<T, TSteps>`** - Basic task unit with optional step tracking
|
|
560
|
+
- **`TaskManager`** - Central orchestrator for task management
|
|
561
|
+
- **`Taskchain`** - Sequential task executor
|
|
562
|
+
- **`TaskParallel`** - Concurrent task executor
|
|
563
|
+
- **`TaskOnce`** - Single-execution task
|
|
564
|
+
- **`TaskLoop`** - Repeating task with conditions
|
|
565
|
+
|
|
566
|
+
### Key Methods
|
|
567
|
+
|
|
568
|
+
#### Task Methods
|
|
569
|
+
- `trigger(input?: T): Promise<any>` - Execute the task
|
|
570
|
+
- `notifyStep(stepName: StepNames<TSteps>): void` - Update current step
|
|
571
|
+
- `getProgress(): number` - Get progress percentage (0-100)
|
|
572
|
+
- `getStepsMetadata(): ITaskStep[]` - Get detailed step information
|
|
573
|
+
- `getMetadata(): ITaskMetadata` - Get complete task metadata
|
|
574
|
+
|
|
575
|
+
#### TaskManager Methods
|
|
576
|
+
- `addTask(task: Task): void` - Register a task
|
|
577
|
+
- `getTaskByName(name: string): Task | undefined` - Retrieve task by name
|
|
578
|
+
- `addAndScheduleTask(task: Task, cronExpression: string): void` - Schedule task
|
|
579
|
+
- `descheduleTaskByName(name: string): void` - Remove scheduling
|
|
580
|
+
- `getTaskMetadata(name: string): ITaskMetadata | null` - Get task metadata
|
|
581
|
+
- `getAllTasksMetadata(): ITaskMetadata[]` - Get all tasks metadata
|
|
582
|
+
- `getScheduledTasks(): IScheduledTaskInfo[]` - List scheduled tasks
|
|
583
|
+
- `addExecuteRemoveTask(task, options?): Promise<ITaskExecutionReport>` - Execute once
|
|
1110
584
|
|
|
1111
585
|
## License and Legal Information
|
|
1112
586
|
|