@push.rocks/taskbuffer 3.2.0 โ 3.5.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 +549 -0
- package/package.json +13 -12
- package/readme.md +429 -930
- 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,611 @@
|
|
|
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.
|
|
31
|
+
## ๐ Quick Start
|
|
43
32
|
|
|
44
|
-
###
|
|
45
|
-
Debounced task execution - prevents rapid repeated executions, only running after a quiet period.
|
|
46
|
-
|
|
47
|
-
### TaskOnce
|
|
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
|
-
##
|
|
110
|
-
|
|
111
|
-
TaskBuffer leverages TypeScript's powerful generics system for complete type safety across your task chains and workflows.
|
|
87
|
+
## ๐ฏ Core Concepts
|
|
112
88
|
|
|
113
|
-
###
|
|
89
|
+
### Task Buffering - Intelligent Request Management
|
|
114
90
|
|
|
115
|
-
|
|
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
|
-
|
|
155
|
-
Tasks can accept setup values through generics, perfect for configuration:
|
|
156
103
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
108
|
```
|
|
186
109
|
|
|
187
|
-
|
|
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
|
|
188
115
|
|
|
189
|
-
|
|
116
|
+
### Task Chains - Sequential Workflows
|
|
117
|
+
|
|
118
|
+
Build complex workflows with automatic data flow:
|
|
190
119
|
|
|
191
120
|
```typescript
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
121
|
+
import { Task, Taskchain } from '@push.rocks/taskbuffer';
|
|
122
|
+
|
|
123
|
+
const fetchTask = new Task({
|
|
124
|
+
name: 'FetchData',
|
|
125
|
+
taskFunction: async () => {
|
|
126
|
+
const response = await fetch('/api/data');
|
|
127
|
+
return response.json();
|
|
197
128
|
}
|
|
198
129
|
});
|
|
199
130
|
|
|
200
|
-
const
|
|
201
|
-
name: '
|
|
202
|
-
taskFunction: async (
|
|
203
|
-
return
|
|
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
|
+
}));
|
|
204
139
|
}
|
|
205
140
|
});
|
|
206
141
|
|
|
207
|
-
const
|
|
208
|
-
name: '
|
|
209
|
-
taskFunction: async (
|
|
210
|
-
|
|
142
|
+
const saveTask = new Task({
|
|
143
|
+
name: 'SaveData',
|
|
144
|
+
taskFunction: async (transformedData) => {
|
|
145
|
+
await database.save(transformedData);
|
|
146
|
+
return transformedData.length;
|
|
211
147
|
}
|
|
212
148
|
});
|
|
213
149
|
|
|
214
|
-
//
|
|
215
|
-
const
|
|
216
|
-
name: '
|
|
217
|
-
|
|
150
|
+
// Create and execute chain
|
|
151
|
+
const dataChain = new Taskchain({
|
|
152
|
+
name: 'DataPipeline',
|
|
153
|
+
tasks: [fetchTask, transformTask, saveTask]
|
|
218
154
|
});
|
|
219
155
|
|
|
220
|
-
const
|
|
156
|
+
const savedCount = await dataChain.trigger();
|
|
157
|
+
console.log(`Saved ${savedCount} items`);
|
|
221
158
|
```
|
|
222
159
|
|
|
223
|
-
|
|
160
|
+
### Parallel Execution - Concurrent Processing
|
|
224
161
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
### Step-by-Step Progress
|
|
228
|
-
|
|
229
|
-
Define weighted steps for accurate progress calculation:
|
|
162
|
+
Execute multiple tasks simultaneously:
|
|
230
163
|
|
|
231
164
|
```typescript
|
|
232
|
-
|
|
233
|
-
name: 'DatabaseMigration',
|
|
234
|
-
steps: [
|
|
235
|
-
{ name: 'backup', description: 'Backing up database', percentage: 20 },
|
|
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,
|
|
240
|
-
taskFunction: async () => {
|
|
241
|
-
migrationTask.notifyStep('backup');
|
|
242
|
-
await backupDatabase();
|
|
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%
|
|
256
|
-
}
|
|
257
|
-
});
|
|
165
|
+
import { Taskparallel } from '@push.rocks/taskbuffer';
|
|
258
166
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
167
|
+
const parallel = new Taskparallel({
|
|
168
|
+
name: 'ParallelProcessor',
|
|
169
|
+
tasks: [
|
|
170
|
+
emailTask,
|
|
171
|
+
smsTask,
|
|
172
|
+
pushNotificationTask,
|
|
173
|
+
webhookTask
|
|
174
|
+
]
|
|
266
175
|
});
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Task Metadata Collection
|
|
270
|
-
|
|
271
|
-
Get comprehensive metadata about task execution:
|
|
272
176
|
|
|
273
|
-
|
|
274
|
-
const
|
|
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();
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
// Get complete task metadata
|
|
288
|
-
const metadata = task.getMetadata();
|
|
289
|
-
console.log({
|
|
290
|
-
name: metadata.name,
|
|
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
|
|
298
|
-
});
|
|
177
|
+
// All tasks execute concurrently
|
|
178
|
+
const results = await parallel.trigger(notificationData);
|
|
179
|
+
// results = [emailResult, smsResult, pushResult, webhookResult]
|
|
299
180
|
```
|
|
300
181
|
|
|
301
|
-
###
|
|
182
|
+
### Debounced Tasks - Smart Trigger Coalescing
|
|
302
183
|
|
|
303
|
-
|
|
184
|
+
Coalesce rapid triggers into a single execution after a quiet period:
|
|
304
185
|
|
|
305
186
|
```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
|
-
});
|
|
187
|
+
import { TaskDebounced } from '@push.rocks/taskbuffer';
|
|
321
188
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
189
|
+
const searchTask = new TaskDebounced({
|
|
190
|
+
name: 'SearchQuery',
|
|
191
|
+
debounceTimeInMillis: 300, // Wait 300ms after last trigger
|
|
192
|
+
taskFunction: async (query) => {
|
|
193
|
+
const results = await searchAPI(query);
|
|
194
|
+
return results;
|
|
328
195
|
}
|
|
329
196
|
});
|
|
330
197
|
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
198
|
+
// Rapid typing - only the last query executes
|
|
199
|
+
searchTask.trigger('h');
|
|
200
|
+
searchTask.trigger('he');
|
|
201
|
+
searchTask.trigger('hel');
|
|
202
|
+
searchTask.trigger('hello'); // Only this one executes after 300ms pause
|
|
334
203
|
```
|
|
335
204
|
|
|
336
|
-
###
|
|
205
|
+
### TaskManager - Centralized Orchestration
|
|
337
206
|
|
|
338
|
-
|
|
207
|
+
Manage all your tasks from a single point:
|
|
339
208
|
|
|
340
209
|
```typescript
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
210
|
+
const taskManager = new TaskManager();
|
|
211
|
+
|
|
212
|
+
// Add tasks
|
|
213
|
+
taskManager.addTask(dataProcessor);
|
|
214
|
+
taskManager.addTask(deploymentTask);
|
|
215
|
+
|
|
216
|
+
// Schedule tasks with cron
|
|
217
|
+
taskManager.addAndScheduleTask(backupTask, '0 2 * * *'); // Daily at 2 AM
|
|
218
|
+
taskManager.addAndScheduleTask(healthCheck, '*/5 * * * *'); // Every 5 minutes
|
|
219
|
+
|
|
220
|
+
// Get task metadata
|
|
221
|
+
const metadata = taskManager.getTaskMetadata('DeployApplication');
|
|
222
|
+
console.log(metadata);
|
|
223
|
+
// {
|
|
224
|
+
// name: 'DeployApplication',
|
|
225
|
+
// status: 'idle' | 'running' | 'completed' | 'failed',
|
|
226
|
+
// steps: [...],
|
|
227
|
+
// currentProgress: 75,
|
|
228
|
+
// runCount: 12,
|
|
229
|
+
// lastRun: Date,
|
|
230
|
+
// buffered: false,
|
|
231
|
+
// bufferMax: undefined,
|
|
232
|
+
// version: '1.0.0',
|
|
233
|
+
// timeout: 30000
|
|
234
|
+
// }
|
|
235
|
+
|
|
236
|
+
// Get all scheduled tasks
|
|
237
|
+
const scheduled = taskManager.getScheduledTasks();
|
|
238
|
+
scheduled.forEach(task => {
|
|
239
|
+
console.log(`${task.name}: Next run at ${task.nextRun}`);
|
|
360
240
|
});
|
|
361
241
|
|
|
362
|
-
// Execute
|
|
363
|
-
const report = await
|
|
242
|
+
// Execute and remove pattern
|
|
243
|
+
const report = await taskManager.addExecuteRemoveTask(temporaryTask, {
|
|
364
244
|
trackProgress: true
|
|
365
245
|
});
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
246
|
+
console.log(report);
|
|
247
|
+
// {
|
|
248
|
+
// taskName: 'TempTask',
|
|
249
|
+
// startTime: Date,
|
|
250
|
+
// endTime: Date,
|
|
251
|
+
// duration: 1523,
|
|
252
|
+
// steps: [...],
|
|
253
|
+
// stepsCompleted: ['step1', 'step2'],
|
|
254
|
+
// progress: 100,
|
|
255
|
+
// result: any,
|
|
256
|
+
// error?: Error
|
|
257
|
+
// }
|
|
374
258
|
```
|
|
375
259
|
|
|
376
|
-
|
|
260
|
+
## ๐จ Web Component Dashboard
|
|
377
261
|
|
|
378
|
-
|
|
262
|
+
Visualize your tasks in real-time with the included web component:
|
|
379
263
|
|
|
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
|
-
});
|
|
264
|
+
```html
|
|
265
|
+
<!DOCTYPE html>
|
|
266
|
+
<html>
|
|
267
|
+
<head>
|
|
268
|
+
<script type="module">
|
|
269
|
+
import { TaskManager } from '@push.rocks/taskbuffer';
|
|
270
|
+
import '@push.rocks/taskbuffer/dist_ts_web/taskbuffer-dashboard.js';
|
|
414
271
|
|
|
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
|
|
272
|
+
const taskManager = new TaskManager();
|
|
273
|
+
|
|
274
|
+
// Attach to dashboard
|
|
275
|
+
const dashboard = document.querySelector('taskbuffer-dashboard');
|
|
276
|
+
dashboard.taskManager = taskManager;
|
|
277
|
+
dashboard.refreshInterval = 500; // Update every 500ms
|
|
278
|
+
</script>
|
|
279
|
+
</head>
|
|
280
|
+
<body>
|
|
281
|
+
<taskbuffer-dashboard></taskbuffer-dashboard>
|
|
282
|
+
</body>
|
|
283
|
+
</html>
|
|
451
284
|
```
|
|
452
285
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
}
|
|
286
|
+
The dashboard provides:
|
|
287
|
+
- ๐ Real-time progress bars with step indicators
|
|
288
|
+
- ๐ Task execution history
|
|
289
|
+
- โฐ Scheduled task information
|
|
290
|
+
- ๐ฏ Interactive task controls
|
|
291
|
+
- ๐ Light/dark theme support
|
|
471
292
|
|
|
472
|
-
|
|
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
|
|
477
|
-
```
|
|
293
|
+
## ๐งฉ Advanced Patterns
|
|
478
294
|
|
|
479
|
-
###
|
|
295
|
+
### Dynamic Task Routing
|
|
480
296
|
|
|
481
|
-
|
|
482
|
-
Perfect for real-time data processing where only recent items matter:
|
|
297
|
+
Route tasks based on conditions:
|
|
483
298
|
|
|
484
299
|
```typescript
|
|
485
|
-
const
|
|
486
|
-
name: '
|
|
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
|
-
});
|
|
494
|
-
|
|
495
|
-
// In a real-time stream scenario
|
|
496
|
-
dataStream.on('data', (chunk) => {
|
|
497
|
-
slidingWindowTask.trigger(chunk);
|
|
498
|
-
// Older items automatically dropped when buffer full
|
|
499
|
-
});
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
#### 2. **Throttled Buffer**
|
|
503
|
-
Combine buffering with execution delays for rate limiting:
|
|
504
|
-
|
|
505
|
-
```typescript
|
|
506
|
-
const apiRateLimiter = new Task({
|
|
507
|
-
name: 'RateLimitedAPI',
|
|
300
|
+
const routerTask = new Task({
|
|
301
|
+
name: 'Router',
|
|
508
302
|
taskFunction: async (request) => {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
303
|
+
if (request.priority === 'high') {
|
|
304
|
+
return await expressProcessor.trigger(request);
|
|
305
|
+
} else if (request.size > 1000000) {
|
|
306
|
+
return await bulkProcessor.trigger(request);
|
|
307
|
+
} else {
|
|
308
|
+
return await standardProcessor.trigger(request);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
514
311
|
});
|
|
515
|
-
|
|
516
|
-
// Requests are queued and executed at 1/second
|
|
517
|
-
// Prevents API rate limit violations
|
|
518
312
|
```
|
|
519
313
|
|
|
520
|
-
|
|
521
|
-
|
|
314
|
+
### Task Pools
|
|
315
|
+
|
|
316
|
+
Create reusable task pools for load distribution:
|
|
522
317
|
|
|
523
318
|
```typescript
|
|
524
|
-
class
|
|
525
|
-
private
|
|
319
|
+
class TaskPool {
|
|
320
|
+
private tasks: Task[] = [];
|
|
321
|
+
private currentIndex = 0;
|
|
526
322
|
|
|
527
|
-
constructor(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
});
|
|
323
|
+
constructor(poolSize: number, taskConfig: any) {
|
|
324
|
+
for (let i = 0; i < poolSize; i++) {
|
|
325
|
+
this.tasks.push(new Task({
|
|
326
|
+
...taskConfig,
|
|
327
|
+
name: `${taskConfig.name}_${i}`
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
535
330
|
}
|
|
536
331
|
|
|
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());
|
|
332
|
+
async execute(data: any) {
|
|
333
|
+
const task = this.tasks[this.currentIndex];
|
|
334
|
+
this.currentIndex = (this.currentIndex + 1) % this.tasks.length;
|
|
335
|
+
return await task.trigger(data);
|
|
546
336
|
}
|
|
547
337
|
}
|
|
548
|
-
```
|
|
549
338
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
-
|
|
632
|
-
const fetchTask = new Task({
|
|
633
|
-
name: 'FetchData',
|
|
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],
|
|
339
|
+
const processorPool = new TaskPool(5, {
|
|
340
|
+
name: 'DataProcessor',
|
|
341
|
+
taskFunction: async (data) => processData(data)
|
|
662
342
|
});
|
|
663
|
-
|
|
664
|
-
// Execute the entire chain
|
|
665
|
-
const result = await workflow.trigger();
|
|
666
|
-
console.log(`Processed ${result.saved} items`);
|
|
667
343
|
```
|
|
668
344
|
|
|
669
|
-
###
|
|
345
|
+
### Error Recovery & Retry
|
|
670
346
|
|
|
671
|
-
|
|
347
|
+
Implement robust error handling:
|
|
672
348
|
|
|
673
349
|
```typescript
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
taskArray: tasks,
|
|
350
|
+
const resilientTask = new Task({
|
|
351
|
+
name: 'ResilientTask',
|
|
352
|
+
taskFunction: async (data, retryCount = 0) => {
|
|
353
|
+
try {
|
|
354
|
+
return await riskyOperation(data);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
if (retryCount < 3) {
|
|
357
|
+
console.log(`Retry ${retryCount + 1}/3`);
|
|
358
|
+
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, retryCount)));
|
|
359
|
+
return await resilientTask.trigger(data, retryCount + 1);
|
|
360
|
+
}
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
689
364
|
});
|
|
690
|
-
|
|
691
|
-
// All tasks execute simultaneously
|
|
692
|
-
const [users, posts, comments] = await parallelFetch.trigger();
|
|
693
365
|
```
|
|
694
366
|
|
|
695
|
-
###
|
|
367
|
+
### Task Composition
|
|
696
368
|
|
|
697
|
-
|
|
369
|
+
Compose complex behaviors from simple tasks:
|
|
698
370
|
|
|
699
371
|
```typescript
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
const backupTask = new Task({
|
|
703
|
-
name: 'DatabaseBackup',
|
|
372
|
+
const compositeTask = new Task({
|
|
373
|
+
name: 'CompositeOperation',
|
|
704
374
|
steps: [
|
|
705
|
-
{ name: '
|
|
706
|
-
{ name: '
|
|
375
|
+
{ name: 'validate', description: 'Validating input', percentage: 20 },
|
|
376
|
+
{ name: 'process', description: 'Processing data', percentage: 60 },
|
|
377
|
+
{ name: 'notify', description: 'Sending notifications', percentage: 20 }
|
|
707
378
|
] as const,
|
|
708
|
-
taskFunction: async ()
|
|
709
|
-
|
|
710
|
-
await
|
|
379
|
+
taskFunction: async function(data) {
|
|
380
|
+
this.notifyStep('validate');
|
|
381
|
+
const validated = await validationTask.trigger(data);
|
|
711
382
|
|
|
712
|
-
|
|
713
|
-
await
|
|
383
|
+
this.notifyStep('process');
|
|
384
|
+
const processed = await processingTask.trigger(validated);
|
|
714
385
|
|
|
715
|
-
|
|
716
|
-
|
|
386
|
+
this.notifyStep('notify');
|
|
387
|
+
await notificationTask.trigger(processed);
|
|
388
|
+
|
|
389
|
+
return processed;
|
|
390
|
+
}
|
|
717
391
|
});
|
|
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
392
|
```
|
|
734
393
|
|
|
735
|
-
|
|
394
|
+
## ๐ง Configuration
|
|
736
395
|
|
|
737
|
-
|
|
396
|
+
### Task Options
|
|
738
397
|
|
|
739
398
|
```typescript
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
saveTask.trigger(e.target.value);
|
|
754
|
-
});
|
|
399
|
+
interface TaskOptions<T = undefined, TSteps = []> {
|
|
400
|
+
name?: string; // Task identifier
|
|
401
|
+
taskFunction: Function; // Async function to execute
|
|
402
|
+
buffered?: boolean; // Enable buffering
|
|
403
|
+
bufferMax?: number; // Max concurrent executions
|
|
404
|
+
execDelay?: number; // Min delay between executions
|
|
405
|
+
timeout?: number; // Task timeout in ms
|
|
406
|
+
version?: string; // Task version
|
|
407
|
+
steps?: TSteps; // Progress steps configuration
|
|
408
|
+
taskSetup?: Function; // One-time setup function
|
|
409
|
+
beforeTask?: Function; // Runs before each execution
|
|
410
|
+
afterTask?: Function; // Runs after each execution
|
|
411
|
+
}
|
|
755
412
|
```
|
|
756
413
|
|
|
757
|
-
###
|
|
758
|
-
|
|
759
|
-
Ensure initialization code runs exactly once:
|
|
414
|
+
### TaskManager Options
|
|
760
415
|
|
|
761
416
|
```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
|
-
},
|
|
417
|
+
const taskManager = new TaskManager({
|
|
418
|
+
maxConcurrentTasks: 10, // Global concurrency limit
|
|
419
|
+
defaultTimeout: 30000, // Default task timeout
|
|
420
|
+
logLevel: 'info' // Logging verbosity
|
|
772
421
|
});
|
|
773
|
-
|
|
774
|
-
// Safe to call multiple times - only runs once
|
|
775
|
-
await initTask.trigger();
|
|
776
|
-
await initTask.trigger(); // This won't run again
|
|
777
422
|
```
|
|
778
423
|
|
|
779
|
-
##
|
|
424
|
+
## ๐ Monitoring & Observability
|
|
780
425
|
|
|
781
|
-
### Task
|
|
782
|
-
|
|
783
|
-
Create sophisticated task relationships:
|
|
426
|
+
### Task Events
|
|
784
427
|
|
|
785
428
|
```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
|
-
});
|
|
429
|
+
task.on('started', () => console.log('Task started'));
|
|
430
|
+
task.on('completed', (result) => console.log('Task completed:', result));
|
|
431
|
+
task.on('failed', (error) => console.error('Task failed:', error));
|
|
432
|
+
task.on('stepChange', (step) => console.log('Step:', step.name));
|
|
804
433
|
```
|
|
805
434
|
|
|
806
|
-
###
|
|
807
|
-
|
|
808
|
-
The TaskRunner system enables distributed task execution across multiple workers:
|
|
435
|
+
### Execution Metrics
|
|
809
436
|
|
|
810
437
|
```typescript
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
438
|
+
const metrics = task.getMetrics();
|
|
439
|
+
console.log({
|
|
440
|
+
totalRuns: metrics.runCount,
|
|
441
|
+
averageDuration: metrics.avgDuration,
|
|
442
|
+
successRate: metrics.successRate,
|
|
443
|
+
lastError: metrics.lastError
|
|
816
444
|
});
|
|
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
445
|
```
|
|
859
446
|
|
|
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 ๐ก๏ธ
|
|
447
|
+
## ๐งช Testing
|
|
924
448
|
|
|
925
449
|
```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
|
-
}
|
|
450
|
+
import { expect, tap } from '@git.zone/tstest';
|
|
451
|
+
import { Task } from '@push.rocks/taskbuffer';
|
|
945
452
|
|
|
946
|
-
|
|
947
|
-
|
|
453
|
+
tap.test('Task should execute with progress tracking', async () => {
|
|
454
|
+
const task = new Task({
|
|
455
|
+
name: 'TestTask',
|
|
456
|
+
steps: [
|
|
457
|
+
{ name: 'step1', description: 'Step 1', percentage: 50 },
|
|
458
|
+
{ name: 'step2', description: 'Step 2', percentage: 50 }
|
|
459
|
+
] as const,
|
|
460
|
+
taskFunction: async function() {
|
|
461
|
+
this.notifyStep('step1');
|
|
462
|
+
await new Promise(r => setTimeout(r, 100));
|
|
463
|
+
this.notifyStep('step2');
|
|
464
|
+
return 'done';
|
|
948
465
|
}
|
|
949
|
-
}
|
|
950
|
-
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
const result = await task.trigger();
|
|
469
|
+
expect(result).toEqual('done');
|
|
470
|
+
expect(task.getProgress()).toEqual(100);
|
|
951
471
|
});
|
|
952
472
|
```
|
|
953
473
|
|
|
954
|
-
## Real-World Examples
|
|
474
|
+
## ๐ Real-World Examples
|
|
955
475
|
|
|
956
|
-
### API Rate
|
|
476
|
+
### API Rate Limiter
|
|
957
477
|
|
|
958
478
|
```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
|
-
},
|
|
479
|
+
const apiLimiter = new Task({
|
|
480
|
+
name: 'APIRateLimiter',
|
|
972
481
|
buffered: true,
|
|
973
|
-
bufferMax: 10,
|
|
974
|
-
execDelay: 100, //
|
|
482
|
+
bufferMax: 10, // Max 10 requests per second
|
|
483
|
+
execDelay: 100, // 100ms between requests
|
|
484
|
+
taskFunction: async (endpoint, data) => {
|
|
485
|
+
return await fetch(endpoint, {
|
|
486
|
+
method: 'POST',
|
|
487
|
+
body: JSON.stringify(data)
|
|
488
|
+
});
|
|
489
|
+
}
|
|
975
490
|
});
|
|
976
491
|
```
|
|
977
492
|
|
|
978
|
-
### Database Migration Pipeline
|
|
493
|
+
### Database Migration Pipeline
|
|
979
494
|
|
|
980
495
|
```typescript
|
|
981
496
|
const migrationChain = new Taskchain({
|
|
982
497
|
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();
|
|
498
|
+
tasks: [
|
|
499
|
+
backupDatabaseTask,
|
|
500
|
+
validateSchemaTask,
|
|
501
|
+
runMigrationsTask,
|
|
502
|
+
verifyIntegrityTask,
|
|
503
|
+
updateIndexesTask
|
|
504
|
+
]
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// Execute with rollback on failure
|
|
508
|
+
try {
|
|
509
|
+
await migrationChain.trigger();
|
|
510
|
+
console.log('Migration successful!');
|
|
511
|
+
} catch (error) {
|
|
512
|
+
await rollbackTask.trigger();
|
|
513
|
+
throw error;
|
|
514
|
+
}
|
|
1012
515
|
```
|
|
1013
516
|
|
|
1014
|
-
###
|
|
517
|
+
### Distributed Job Queue
|
|
1015
518
|
|
|
1016
519
|
```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
|
-
});
|
|
520
|
+
const jobQueue = new TaskManager();
|
|
1042
521
|
|
|
1043
|
-
|
|
522
|
+
// Worker tasks
|
|
523
|
+
const imageProcessor = new Task({
|
|
524
|
+
name: 'ImageProcessor',
|
|
525
|
+
buffered: true,
|
|
526
|
+
bufferMax: 5,
|
|
527
|
+
steps: [
|
|
528
|
+
{ name: 'download', description: 'Downloading', percentage: 20 },
|
|
529
|
+
{ name: 'resize', description: 'Resizing', percentage: 40 },
|
|
530
|
+
{ name: 'optimize', description: 'Optimizing', percentage: 30 },
|
|
531
|
+
{ name: 'upload', description: 'Uploading', percentage: 10 }
|
|
532
|
+
] as const,
|
|
533
|
+
taskFunction: async function(job) {
|
|
534
|
+
this.notifyStep('download');
|
|
535
|
+
const image = await downloadImage(job.url);
|
|
536
|
+
|
|
537
|
+
this.notifyStep('resize');
|
|
538
|
+
const resized = await resizeImage(image, job.dimensions);
|
|
539
|
+
|
|
540
|
+
this.notifyStep('optimize');
|
|
541
|
+
const optimized = await optimizeImage(resized);
|
|
542
|
+
|
|
543
|
+
this.notifyStep('upload');
|
|
544
|
+
return await uploadToCDN(optimized);
|
|
545
|
+
}
|
|
1044
546
|
});
|
|
1045
547
|
|
|
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
|
-
});
|
|
548
|
+
jobQueue.addTask(imageProcessor);
|
|
549
|
+
|
|
550
|
+
// Process incoming jobs
|
|
551
|
+
messageQueue.on('job', async (job) => {
|
|
552
|
+
const result = await jobQueue.getTaskByName('ImageProcessor').trigger(job);
|
|
553
|
+
await messageQueue.ack(job.id, result);
|
|
1060
554
|
});
|
|
1061
555
|
```
|
|
1062
556
|
|
|
1063
|
-
##
|
|
557
|
+
## ๐ Performance Tips
|
|
1064
558
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
559
|
+
1. **Use Buffering Wisely** - Enable buffering for I/O-bound tasks
|
|
560
|
+
2. **Set Appropriate Delays** - Use `execDelay` to prevent API rate limits
|
|
561
|
+
3. **Leverage Task Pools** - Distribute load across multiple task instances
|
|
562
|
+
4. **Monitor Progress** - Use step tracking for long-running operations
|
|
563
|
+
5. **Clean Up** - Use `addExecuteRemoveTask` for one-time operations
|
|
1068
564
|
|
|
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
|
-
});
|
|
565
|
+
## ๐ Debugging
|
|
1088
566
|
|
|
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
|
-
});
|
|
567
|
+
Enable detailed logging:
|
|
1101
568
|
|
|
1102
|
-
|
|
1103
|
-
|
|
569
|
+
```typescript
|
|
570
|
+
import { logger } from '@push.rocks/smartlog';
|
|
1104
571
|
|
|
1105
|
-
|
|
572
|
+
logger.enableConsole();
|
|
573
|
+
logger.level = 'debug';
|
|
574
|
+
|
|
575
|
+
// Tasks will now output detailed execution logs
|
|
576
|
+
```
|
|
1106
577
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
578
|
+
## ๐ API Reference
|
|
579
|
+
|
|
580
|
+
### Core Classes
|
|
581
|
+
|
|
582
|
+
- **`Task<T, TSteps>`** - Basic task unit with optional step tracking
|
|
583
|
+
- **`TaskManager`** - Central orchestrator for task management
|
|
584
|
+
- **`Taskchain`** - Sequential task executor
|
|
585
|
+
- **`Taskparallel`** - Concurrent task executor
|
|
586
|
+
- **`TaskOnce`** - Single-execution task
|
|
587
|
+
- **`TaskDebounced`** - Debounced task that waits for a pause in triggers
|
|
588
|
+
- **`TaskRunner`** - Sequential task runner with scheduling support
|
|
589
|
+
- **`distributedCoordination`** - Namespace for distributed task coordination
|
|
590
|
+
|
|
591
|
+
### Key Methods
|
|
592
|
+
|
|
593
|
+
#### Task Methods
|
|
594
|
+
- `trigger(input?: T): Promise<any>` - Execute the task
|
|
595
|
+
- `notifyStep(stepName: StepNames<TSteps>): void` - Update current step
|
|
596
|
+
- `getProgress(): number` - Get progress percentage (0-100)
|
|
597
|
+
- `getStepsMetadata(): ITaskStep[]` - Get detailed step information
|
|
598
|
+
- `getMetadata(): ITaskMetadata` - Get complete task metadata
|
|
599
|
+
|
|
600
|
+
#### TaskManager Methods
|
|
601
|
+
- `addTask(task: Task): void` - Register a task
|
|
602
|
+
- `getTaskByName(name: string): Task | undefined` - Retrieve task by name
|
|
603
|
+
- `addAndScheduleTask(task: Task, cronExpression: string): void` - Schedule task
|
|
604
|
+
- `descheduleTaskByName(name: string): void` - Remove scheduling
|
|
605
|
+
- `getTaskMetadata(name: string): ITaskMetadata | null` - Get task metadata
|
|
606
|
+
- `getAllTasksMetadata(): ITaskMetadata[]` - Get all tasks metadata
|
|
607
|
+
- `getScheduledTasks(): IScheduledTaskInfo[]` - List scheduled tasks
|
|
608
|
+
- `addExecuteRemoveTask(task, options?): Promise<ITaskExecutionReport>` - Execute once
|
|
1110
609
|
|
|
1111
610
|
## License and Legal Information
|
|
1112
611
|
|