@push.rocks/taskbuffer 3.1.8 → 3.1.10
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/dist_bundle/bundle.js +18 -8
- package/dist_bundle/bundle.js.map +2 -2
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/taskbuffer.classes.bufferrunner.js +1 -1
- package/dist_ts/taskbuffer.classes.task.js +9 -4
- package/dist_ts/taskbuffer.classes.taskchain.js +1 -1
- package/dist_ts/taskbuffer.classes.taskdebounced.js +1 -1
- package/dist_ts/taskbuffer.classes.taskmanager.js +2 -2
- package/dist_ts/taskbuffer.classes.taskrunner.js +1 -1
- package/dist_ts/taskbuffer.plugins.d.ts +1 -1
- package/dist_ts/taskbuffer.plugins.js +2 -2
- package/npmextra.json +1 -1
- package/package.json +3 -3
- package/readme.md +407 -77
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/taskbuffer.classes.bufferrunner.ts +2 -3
- package/ts/taskbuffer.classes.distributedcoordinator.ts +2 -2
- package/ts/taskbuffer.classes.task.ts +15 -6
- package/ts/taskbuffer.classes.taskchain.ts +6 -2
- package/ts/taskbuffer.classes.taskdebounced.ts +3 -1
- package/ts/taskbuffer.classes.taskmanager.ts +13 -4
- package/ts/taskbuffer.classes.taskrunner.ts +2 -1
- package/ts/taskbuffer.plugins.ts +9 -1
package/readme.md
CHANGED
|
@@ -29,21 +29,27 @@ In the modern JavaScript ecosystem, managing asynchronous tasks efficiently is c
|
|
|
29
29
|
## Core Concepts 🎓
|
|
30
30
|
|
|
31
31
|
### Task
|
|
32
|
+
|
|
32
33
|
The fundamental unit of work. A task wraps an asynchronous function and provides powerful execution control.
|
|
33
34
|
|
|
34
35
|
### Taskchain
|
|
36
|
+
|
|
35
37
|
Sequential task execution - tasks run one after another, with results passed along the chain.
|
|
36
38
|
|
|
37
39
|
### Taskparallel
|
|
40
|
+
|
|
38
41
|
Parallel task execution - multiple tasks run simultaneously for maximum performance.
|
|
39
42
|
|
|
40
43
|
### TaskManager
|
|
44
|
+
|
|
41
45
|
Centralized task scheduling and management using cron expressions.
|
|
42
46
|
|
|
43
47
|
### TaskDebounced
|
|
48
|
+
|
|
44
49
|
Debounced task execution - prevents rapid repeated executions, only running after a quiet period.
|
|
45
50
|
|
|
46
51
|
### TaskOnce
|
|
52
|
+
|
|
47
53
|
Singleton task execution - ensures a task runs exactly once, perfect for initialization routines.
|
|
48
54
|
|
|
49
55
|
## Quick Start 🏁
|
|
@@ -59,13 +65,329 @@ const myTask = new Task({
|
|
|
59
65
|
taskFunction: async () => {
|
|
60
66
|
const data = await fetchData();
|
|
61
67
|
return processData(data);
|
|
62
|
-
}
|
|
68
|
+
},
|
|
63
69
|
});
|
|
64
70
|
|
|
65
71
|
// Execute the task
|
|
66
72
|
const result = await myTask.trigger();
|
|
67
73
|
```
|
|
68
74
|
|
|
75
|
+
## TypeScript Generics Support 🔬
|
|
76
|
+
|
|
77
|
+
TaskBuffer leverages TypeScript's powerful generics system for complete type safety across your task chains and workflows.
|
|
78
|
+
|
|
79
|
+
### Generic Task Functions
|
|
80
|
+
|
|
81
|
+
Tasks support generic type parameters for both input and output types:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { Task, ITaskFunction } from '@push.rocks/taskbuffer';
|
|
85
|
+
|
|
86
|
+
// Define typed interfaces
|
|
87
|
+
interface UserData {
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
email: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface ProcessedUser {
|
|
94
|
+
userId: string;
|
|
95
|
+
displayName: string;
|
|
96
|
+
normalized: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Create strongly typed tasks
|
|
100
|
+
const processUserTask = new Task<UserData, ProcessedUser>({
|
|
101
|
+
name: 'ProcessUser',
|
|
102
|
+
taskFunction: async (user: UserData): Promise<ProcessedUser> => {
|
|
103
|
+
return {
|
|
104
|
+
userId: user.id,
|
|
105
|
+
displayName: user.name.toUpperCase(),
|
|
106
|
+
normalized: true
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Type safety enforced at compile time
|
|
112
|
+
const result: ProcessedUser = await processUserTask.trigger({
|
|
113
|
+
id: '123',
|
|
114
|
+
name: 'John Doe',
|
|
115
|
+
email: 'john@example.com'
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Generic Setup Values
|
|
120
|
+
|
|
121
|
+
Tasks can accept setup values through generics, perfect for configuration:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
interface TaskConfig {
|
|
125
|
+
apiEndpoint: string;
|
|
126
|
+
retryCount: number;
|
|
127
|
+
timeout: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const configuredTask = new Task<TaskConfig>({
|
|
131
|
+
name: 'ConfiguredTask',
|
|
132
|
+
taskSetup: async () => ({
|
|
133
|
+
apiEndpoint: 'https://api.example.com',
|
|
134
|
+
retryCount: 3,
|
|
135
|
+
timeout: 5000
|
|
136
|
+
}),
|
|
137
|
+
taskFunction: async (data: any, setupValue: TaskConfig) => {
|
|
138
|
+
// setupValue is fully typed!
|
|
139
|
+
for (let i = 0; i < setupValue.retryCount; i++) {
|
|
140
|
+
try {
|
|
141
|
+
return await fetchWithTimeout(
|
|
142
|
+
setupValue.apiEndpoint,
|
|
143
|
+
setupValue.timeout
|
|
144
|
+
);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (i === setupValue.retryCount - 1) throw error;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Type-Safe Task Chains
|
|
154
|
+
|
|
155
|
+
Chain tasks with preserved type flow:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// Each task knows its input and output types
|
|
159
|
+
const fetchTask = new Task<void, UserData[]>({
|
|
160
|
+
name: 'FetchUsers',
|
|
161
|
+
taskFunction: async (): Promise<UserData[]> => {
|
|
162
|
+
return await api.getUsers();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const filterTask = new Task<UserData[], UserData[]>({
|
|
167
|
+
name: 'FilterActive',
|
|
168
|
+
taskFunction: async (users: UserData[]): Promise<UserData[]> => {
|
|
169
|
+
return users.filter(user => user.isActive);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const mapTask = new Task<UserData[], ProcessedUser[]>({
|
|
174
|
+
name: 'MapToProcessed',
|
|
175
|
+
taskFunction: async (users: UserData[]): Promise<ProcessedUser[]> => {
|
|
176
|
+
return users.map(transformUser);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Type safety flows through the chain
|
|
181
|
+
const chain = new Taskchain({
|
|
182
|
+
name: 'UserPipeline',
|
|
183
|
+
taskArray: [fetchTask, filterTask, mapTask]
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const finalResult: ProcessedUser[] = await chain.trigger();
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Buffer Behavior Deep Dive 🌊
|
|
190
|
+
|
|
191
|
+
The buffer system in TaskBuffer provides intelligent control over concurrent executions, preventing system overload while maximizing throughput.
|
|
192
|
+
|
|
193
|
+
### How Buffering Works
|
|
194
|
+
|
|
195
|
+
When a task is buffered, TaskBuffer manages a queue of executions:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
const bufferedTask = new Task({
|
|
199
|
+
name: 'BufferedOperation',
|
|
200
|
+
taskFunction: async (data) => {
|
|
201
|
+
console.log(`Processing: ${data}`);
|
|
202
|
+
await simulateWork();
|
|
203
|
+
return `Processed: ${data}`;
|
|
204
|
+
},
|
|
205
|
+
buffered: true,
|
|
206
|
+
bufferMax: 3 // Maximum 3 concurrent executions
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Trigger 10 executions rapidly
|
|
210
|
+
for (let i = 0; i < 10; i++) {
|
|
211
|
+
bufferedTask.trigger(`Item ${i}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// What happens:
|
|
215
|
+
// 1. First 3 tasks start immediately
|
|
216
|
+
// 2. Items 4-10 are queued
|
|
217
|
+
// 3. As each task completes, next queued item starts
|
|
218
|
+
// 4. Never more than 3 tasks running simultaneously
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Buffer Truncation Behavior
|
|
222
|
+
|
|
223
|
+
When buffer limit is reached, new calls are intelligently managed:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
const truncatingTask = new Task({
|
|
227
|
+
name: 'TruncatingBuffer',
|
|
228
|
+
taskFunction: async (data) => {
|
|
229
|
+
await processData(data);
|
|
230
|
+
},
|
|
231
|
+
buffered: true,
|
|
232
|
+
bufferMax: 5 // Maximum 5 in buffer
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Rapid fire 100 calls
|
|
236
|
+
for (let i = 0; i < 100; i++) {
|
|
237
|
+
truncatingTask.trigger(`Data ${i}`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Buffer behavior:
|
|
241
|
+
// - First 5 calls: Added to buffer and start processing
|
|
242
|
+
// - Calls 6-100: Each overwrites the 5th buffer slot
|
|
243
|
+
// - Result: Only processes items 0,1,2,3, and 99 (last one)
|
|
244
|
+
// - This prevents memory overflow in high-frequency scenarios
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Advanced Buffer Strategies
|
|
248
|
+
|
|
249
|
+
#### 1. **Sliding Window Buffer**
|
|
250
|
+
Perfect for real-time data processing where only recent items matter:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const slidingWindowTask = new Task({
|
|
254
|
+
name: 'SlidingWindow',
|
|
255
|
+
taskFunction: async (data) => {
|
|
256
|
+
return await analyzeRecentData(data);
|
|
257
|
+
},
|
|
258
|
+
buffered: true,
|
|
259
|
+
bufferMax: 10, // Keep last 10 items
|
|
260
|
+
execDelay: 100 // Process every 100ms
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// In a real-time stream scenario
|
|
264
|
+
dataStream.on('data', (chunk) => {
|
|
265
|
+
slidingWindowTask.trigger(chunk);
|
|
266
|
+
// Older items automatically dropped when buffer full
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### 2. **Throttled Buffer**
|
|
271
|
+
Combine buffering with execution delays for rate limiting:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
const apiRateLimiter = new Task({
|
|
275
|
+
name: 'RateLimitedAPI',
|
|
276
|
+
taskFunction: async (request) => {
|
|
277
|
+
return await api.call(request);
|
|
278
|
+
},
|
|
279
|
+
buffered: true,
|
|
280
|
+
bufferMax: 10, // Max 10 queued requests
|
|
281
|
+
execDelay: 1000 // 1 second between executions
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Requests are queued and executed at 1/second
|
|
285
|
+
// Prevents API rate limit violations
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### 3. **Priority Buffer** (Custom Implementation)
|
|
289
|
+
Implement priority queuing with buffer management:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
class PriorityBufferedTask extends Task {
|
|
293
|
+
private priorityQueue: Array<{data: any, priority: number}> = [];
|
|
294
|
+
|
|
295
|
+
constructor(options) {
|
|
296
|
+
super({
|
|
297
|
+
...options,
|
|
298
|
+
taskFunction: async (item) => {
|
|
299
|
+
// Process based on priority
|
|
300
|
+
return await this.processByPriority(item);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
triggerWithPriority(data: any, priority: number) {
|
|
306
|
+
if (this.priorityQueue.length >= this.bufferMax) {
|
|
307
|
+
// Remove lowest priority item if buffer full
|
|
308
|
+
this.priorityQueue.sort((a, b) => b.priority - a.priority);
|
|
309
|
+
this.priorityQueue.pop();
|
|
310
|
+
}
|
|
311
|
+
this.priorityQueue.push({data, priority});
|
|
312
|
+
this.priorityQueue.sort((a, b) => b.priority - a.priority);
|
|
313
|
+
return this.trigger(this.priorityQueue.shift());
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Buffer Monitoring
|
|
319
|
+
|
|
320
|
+
Track buffer utilization and performance:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
const monitoredTask = new Task({
|
|
324
|
+
name: 'MonitoredBuffer',
|
|
325
|
+
taskFunction: async (data) => {
|
|
326
|
+
const startTime = Date.now();
|
|
327
|
+
const result = await processData(data);
|
|
328
|
+
console.log(`Processing time: ${Date.now() - startTime}ms`);
|
|
329
|
+
console.log(`Buffer utilization: ${monitoredTask.bufferRunner.bufferCounter}/${monitoredTask.bufferMax}`);
|
|
330
|
+
return result;
|
|
331
|
+
},
|
|
332
|
+
buffered: true,
|
|
333
|
+
bufferMax: 20
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Monitor buffer saturation
|
|
337
|
+
setInterval(() => {
|
|
338
|
+
const utilization = (monitoredTask.bufferRunner.bufferCounter / monitoredTask.bufferMax) * 100;
|
|
339
|
+
if (utilization > 80) {
|
|
340
|
+
console.warn(`Buffer near capacity: ${utilization.toFixed(1)}%`);
|
|
341
|
+
}
|
|
342
|
+
}, 1000);
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Buffer Best Practices
|
|
346
|
+
|
|
347
|
+
1. **Choose appropriate buffer sizes**:
|
|
348
|
+
- I/O operations: 5-10 concurrent
|
|
349
|
+
- CPU-intensive: Number of cores
|
|
350
|
+
- API calls: Based on rate limits
|
|
351
|
+
|
|
352
|
+
2. **Handle buffer overflow gracefully**:
|
|
353
|
+
```typescript
|
|
354
|
+
const task = new Task({
|
|
355
|
+
taskFunction: async (data) => {
|
|
356
|
+
try {
|
|
357
|
+
return await process(data);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
if (error.code === 'BUFFER_OVERFLOW') {
|
|
360
|
+
// Implement backoff strategy
|
|
361
|
+
await delay(1000);
|
|
362
|
+
return task.trigger(data);
|
|
363
|
+
}
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
buffered: true,
|
|
368
|
+
bufferMax: 10
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
3. **Monitor and adjust dynamically**:
|
|
373
|
+
```typescript
|
|
374
|
+
// Adjust buffer size based on system load
|
|
375
|
+
const adaptiveTask = new Task({
|
|
376
|
+
name: 'AdaptiveBuffer',
|
|
377
|
+
taskFunction: async (data) => {
|
|
378
|
+
const cpuLoad = await getSystemLoad();
|
|
379
|
+
if (cpuLoad > 0.8) {
|
|
380
|
+
adaptiveTask.bufferMax = Math.max(2, adaptiveTask.bufferMax - 1);
|
|
381
|
+
} else if (cpuLoad < 0.5) {
|
|
382
|
+
adaptiveTask.bufferMax = Math.min(20, adaptiveTask.bufferMax + 1);
|
|
383
|
+
}
|
|
384
|
+
return await process(data);
|
|
385
|
+
},
|
|
386
|
+
buffered: true,
|
|
387
|
+
bufferMax: 10
|
|
388
|
+
});
|
|
389
|
+
```
|
|
390
|
+
|
|
69
391
|
### Buffered Execution (Rate Limiting)
|
|
70
392
|
|
|
71
393
|
Perfect for API calls or database operations that need throttling:
|
|
@@ -78,7 +400,7 @@ const apiTask = new Task({
|
|
|
78
400
|
},
|
|
79
401
|
buffered: true,
|
|
80
402
|
bufferMax: 3, // Maximum 3 concurrent executions
|
|
81
|
-
execDelay: 1000 // Wait 1 second between executions
|
|
403
|
+
execDelay: 1000, // Wait 1 second between executions
|
|
82
404
|
});
|
|
83
405
|
|
|
84
406
|
// These will be automatically throttled
|
|
@@ -99,18 +421,18 @@ const fetchTask = new Task({
|
|
|
99
421
|
taskFunction: async () => {
|
|
100
422
|
const response = await fetch('/api/data');
|
|
101
423
|
return response.json();
|
|
102
|
-
}
|
|
424
|
+
},
|
|
103
425
|
});
|
|
104
426
|
|
|
105
427
|
const transformTask = new Task({
|
|
106
428
|
name: 'TransformData',
|
|
107
429
|
taskFunction: async (data) => {
|
|
108
|
-
return data.map(item => ({
|
|
430
|
+
return data.map((item) => ({
|
|
109
431
|
...item,
|
|
110
432
|
processed: true,
|
|
111
|
-
timestamp: Date.now()
|
|
433
|
+
timestamp: Date.now(),
|
|
112
434
|
}));
|
|
113
|
-
}
|
|
435
|
+
},
|
|
114
436
|
});
|
|
115
437
|
|
|
116
438
|
const saveTask = new Task({
|
|
@@ -118,12 +440,12 @@ const saveTask = new Task({
|
|
|
118
440
|
taskFunction: async (transformedData) => {
|
|
119
441
|
await database.bulkInsert(transformedData);
|
|
120
442
|
return { saved: transformedData.length };
|
|
121
|
-
}
|
|
443
|
+
},
|
|
122
444
|
});
|
|
123
445
|
|
|
124
446
|
const workflow = new Taskchain({
|
|
125
447
|
name: 'DataPipeline',
|
|
126
|
-
taskArray: [fetchTask, transformTask, saveTask]
|
|
448
|
+
taskArray: [fetchTask, transformTask, saveTask],
|
|
127
449
|
});
|
|
128
450
|
|
|
129
451
|
// Execute the entire chain
|
|
@@ -138,18 +460,19 @@ Execute multiple independent tasks simultaneously:
|
|
|
138
460
|
```typescript
|
|
139
461
|
import { Task, Taskparallel } from '@push.rocks/taskbuffer';
|
|
140
462
|
|
|
141
|
-
const tasks = ['user', 'posts', 'comments'].map(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
463
|
+
const tasks = ['user', 'posts', 'comments'].map(
|
|
464
|
+
(resource) =>
|
|
465
|
+
new Task({
|
|
466
|
+
name: `Fetch${resource}`,
|
|
467
|
+
taskFunction: async () => {
|
|
468
|
+
const data = await fetch(`/api/${resource}`);
|
|
469
|
+
return data.json();
|
|
470
|
+
},
|
|
471
|
+
}),
|
|
149
472
|
);
|
|
150
473
|
|
|
151
474
|
const parallelFetch = new Taskparallel({
|
|
152
|
-
taskArray: tasks
|
|
475
|
+
taskArray: tasks,
|
|
153
476
|
});
|
|
154
477
|
|
|
155
478
|
// All tasks execute simultaneously
|
|
@@ -168,7 +491,7 @@ const backupTask = new Task({
|
|
|
168
491
|
taskFunction: async () => {
|
|
169
492
|
await performBackup();
|
|
170
493
|
console.log(`Backup completed at ${new Date().toISOString()}`);
|
|
171
|
-
}
|
|
494
|
+
},
|
|
172
495
|
});
|
|
173
496
|
|
|
174
497
|
const manager = new TaskManager();
|
|
@@ -197,7 +520,7 @@ const saveTask = new TaskDebounced({
|
|
|
197
520
|
await saveToDatabase(content);
|
|
198
521
|
console.log('Content saved');
|
|
199
522
|
},
|
|
200
|
-
debounceTimeInMillis: 2000 // Wait 2 seconds of inactivity
|
|
523
|
+
debounceTimeInMillis: 2000, // Wait 2 seconds of inactivity
|
|
201
524
|
});
|
|
202
525
|
|
|
203
526
|
// Rapid calls will be debounced
|
|
@@ -220,7 +543,7 @@ const initTask = new TaskOnce({
|
|
|
220
543
|
await cache.initialize();
|
|
221
544
|
await loadConfiguration();
|
|
222
545
|
console.log('System initialized');
|
|
223
|
-
}
|
|
546
|
+
},
|
|
224
547
|
});
|
|
225
548
|
|
|
226
549
|
// Safe to call multiple times - only runs once
|
|
@@ -242,7 +565,7 @@ const validationTask = new Task({
|
|
|
242
565
|
throw new Error('Validation failed');
|
|
243
566
|
}
|
|
244
567
|
return data;
|
|
245
|
-
}
|
|
568
|
+
},
|
|
246
569
|
});
|
|
247
570
|
|
|
248
571
|
const mainTask = new Task({
|
|
@@ -250,8 +573,8 @@ const mainTask = new Task({
|
|
|
250
573
|
taskFunction: async (data) => {
|
|
251
574
|
return await complexProcessing(data);
|
|
252
575
|
},
|
|
253
|
-
preTask: validationTask,
|
|
254
|
-
afterTask: cleanupTask
|
|
576
|
+
preTask: validationTask, // Runs before main task
|
|
577
|
+
afterTask: cleanupTask, // Runs after main task
|
|
255
578
|
});
|
|
256
579
|
```
|
|
257
580
|
|
|
@@ -264,7 +587,7 @@ import { TaskRunner } from '@push.rocks/taskbuffer';
|
|
|
264
587
|
|
|
265
588
|
const runner = new TaskRunner({
|
|
266
589
|
name: 'WorkerNode1',
|
|
267
|
-
maxConcurrentTasks: 5
|
|
590
|
+
maxConcurrentTasks: 5,
|
|
268
591
|
});
|
|
269
592
|
|
|
270
593
|
// Register tasks this runner can handle
|
|
@@ -282,11 +605,13 @@ Fine-tune concurrent execution behavior:
|
|
|
282
605
|
```typescript
|
|
283
606
|
const task = new Task({
|
|
284
607
|
name: 'ResourceIntensive',
|
|
285
|
-
taskFunction: async () => {
|
|
608
|
+
taskFunction: async () => {
|
|
609
|
+
/* ... */
|
|
610
|
+
},
|
|
286
611
|
buffered: true,
|
|
287
|
-
bufferMax: 5,
|
|
288
|
-
execDelay: 100,
|
|
289
|
-
timeout: 30000
|
|
612
|
+
bufferMax: 5, // Max 5 concurrent
|
|
613
|
+
execDelay: 100, // 100ms between starts
|
|
614
|
+
timeout: 30000, // 30 second timeout
|
|
290
615
|
});
|
|
291
616
|
```
|
|
292
617
|
|
|
@@ -297,14 +622,18 @@ TaskBuffer automatically detects and prevents circular dependencies:
|
|
|
297
622
|
```typescript
|
|
298
623
|
const taskA = new Task({
|
|
299
624
|
name: 'TaskA',
|
|
300
|
-
taskFunction: async () => {
|
|
301
|
-
|
|
625
|
+
taskFunction: async () => {
|
|
626
|
+
/* ... */
|
|
627
|
+
},
|
|
628
|
+
preTask: taskB, // This would create a cycle
|
|
302
629
|
});
|
|
303
630
|
|
|
304
631
|
const taskB = new Task({
|
|
305
632
|
name: 'TaskB',
|
|
306
|
-
taskFunction: async () => {
|
|
307
|
-
|
|
633
|
+
taskFunction: async () => {
|
|
634
|
+
/* ... */
|
|
635
|
+
},
|
|
636
|
+
preTask: taskA, // Circular dependency detected!
|
|
308
637
|
});
|
|
309
638
|
```
|
|
310
639
|
|
|
@@ -314,20 +643,21 @@ Create tasks on-the-fly based on runtime conditions:
|
|
|
314
643
|
|
|
315
644
|
```typescript
|
|
316
645
|
const dynamicWorkflow = async (config: Config) => {
|
|
317
|
-
const tasks = config.steps.map(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
646
|
+
const tasks = config.steps.map(
|
|
647
|
+
(step) =>
|
|
648
|
+
new Task({
|
|
649
|
+
name: step.name,
|
|
650
|
+
taskFunction: async (input) => {
|
|
651
|
+
return await processStep(step, input);
|
|
652
|
+
},
|
|
653
|
+
}),
|
|
324
654
|
);
|
|
325
|
-
|
|
655
|
+
|
|
326
656
|
const chain = new Taskchain({
|
|
327
657
|
name: 'DynamicWorkflow',
|
|
328
|
-
taskArray: tasks
|
|
658
|
+
taskArray: tasks,
|
|
329
659
|
});
|
|
330
|
-
|
|
660
|
+
|
|
331
661
|
return await chain.trigger();
|
|
332
662
|
};
|
|
333
663
|
```
|
|
@@ -336,35 +666,35 @@ const dynamicWorkflow = async (config: Config) => {
|
|
|
336
666
|
|
|
337
667
|
### Task Options
|
|
338
668
|
|
|
339
|
-
| Option
|
|
340
|
-
|
|
341
|
-
| `name`
|
|
342
|
-
| `taskFunction` | `Function` | Async function to execute
|
|
343
|
-
| `buffered`
|
|
344
|
-
| `bufferMax`
|
|
345
|
-
| `execDelay`
|
|
346
|
-
| `timeout`
|
|
347
|
-
| `preTask`
|
|
348
|
-
| `afterTask`
|
|
669
|
+
| Option | Type | Description |
|
|
670
|
+
| -------------- | ---------- | ------------------------------ |
|
|
671
|
+
| `name` | `string` | Unique identifier for the task |
|
|
672
|
+
| `taskFunction` | `Function` | Async function to execute |
|
|
673
|
+
| `buffered` | `boolean` | Enable buffer management |
|
|
674
|
+
| `bufferMax` | `number` | Maximum concurrent executions |
|
|
675
|
+
| `execDelay` | `number` | Delay between executions (ms) |
|
|
676
|
+
| `timeout` | `number` | Task timeout (ms) |
|
|
677
|
+
| `preTask` | `Task` | Task to run before |
|
|
678
|
+
| `afterTask` | `Task` | Task to run after |
|
|
349
679
|
|
|
350
680
|
### TaskManager Methods
|
|
351
681
|
|
|
352
|
-
| Method
|
|
353
|
-
|
|
354
|
-
| `addTask(task, cronExpression)` | Add and schedule a task
|
|
355
|
-
| `removeTask(taskName)`
|
|
356
|
-
| `start()`
|
|
357
|
-
| `stop()`
|
|
358
|
-
| `getStats()`
|
|
682
|
+
| Method | Description |
|
|
683
|
+
| ------------------------------- | ------------------------ |
|
|
684
|
+
| `addTask(task, cronExpression)` | Add and schedule a task |
|
|
685
|
+
| `removeTask(taskName)` | Remove a scheduled task |
|
|
686
|
+
| `start()` | Start the scheduler |
|
|
687
|
+
| `stop()` | Stop the scheduler |
|
|
688
|
+
| `getStats()` | Get execution statistics |
|
|
359
689
|
|
|
360
690
|
### Taskchain Methods
|
|
361
691
|
|
|
362
|
-
| Method
|
|
363
|
-
|
|
364
|
-
| `addTask(task)`
|
|
365
|
-
| `removeTask(taskName)`
|
|
366
|
-
| `trigger(initialValue)` | Execute the chain
|
|
367
|
-
| `reset()`
|
|
692
|
+
| Method | Description |
|
|
693
|
+
| ----------------------- | ---------------------- |
|
|
694
|
+
| `addTask(task)` | Add task to chain |
|
|
695
|
+
| `removeTask(taskName)` | Remove task from chain |
|
|
696
|
+
| `trigger(initialValue)` | Execute the chain |
|
|
697
|
+
| `reset()` | Reset chain state |
|
|
368
698
|
|
|
369
699
|
## Performance Tips 🏎️
|
|
370
700
|
|
|
@@ -385,17 +715,17 @@ const robustTask = new Task({
|
|
|
385
715
|
} catch (error) {
|
|
386
716
|
// Log error
|
|
387
717
|
console.error(`Task failed: ${error.message}`);
|
|
388
|
-
|
|
718
|
+
|
|
389
719
|
// Optionally retry
|
|
390
720
|
if (error.retryable) {
|
|
391
721
|
return await riskyOperation(input);
|
|
392
722
|
}
|
|
393
|
-
|
|
723
|
+
|
|
394
724
|
// Or return default value
|
|
395
725
|
return defaultValue;
|
|
396
726
|
}
|
|
397
727
|
},
|
|
398
|
-
timeout: 5000 // Fail if takes longer than 5 seconds
|
|
728
|
+
timeout: 5000, // Fail if takes longer than 5 seconds
|
|
399
729
|
});
|
|
400
730
|
```
|
|
401
731
|
|
|
@@ -410,8 +740,8 @@ const apiClient = new Task({
|
|
|
410
740
|
return await fetch(`https://api.example.com${endpoint}`);
|
|
411
741
|
},
|
|
412
742
|
buffered: true,
|
|
413
|
-
bufferMax: 10,
|
|
414
|
-
execDelay: 100
|
|
743
|
+
bufferMax: 10, // 10 requests
|
|
744
|
+
execDelay: 100, // Per 100ms = 100 req/s max
|
|
415
745
|
});
|
|
416
746
|
```
|
|
417
747
|
|
|
@@ -425,8 +755,8 @@ const migrationChain = new Taskchain({
|
|
|
425
755
|
schemaUpdateTask,
|
|
426
756
|
dataTransformTask,
|
|
427
757
|
validationTask,
|
|
428
|
-
cleanupTask
|
|
429
|
-
]
|
|
758
|
+
cleanupTask,
|
|
759
|
+
],
|
|
430
760
|
});
|
|
431
761
|
```
|
|
432
762
|
|
|
@@ -435,7 +765,7 @@ const migrationChain = new Taskchain({
|
|
|
435
765
|
```typescript
|
|
436
766
|
const healthMonitor = new TaskManager();
|
|
437
767
|
|
|
438
|
-
services.forEach(service => {
|
|
768
|
+
services.forEach((service) => {
|
|
439
769
|
const healthCheck = new Task({
|
|
440
770
|
name: `HealthCheck:${service.name}`,
|
|
441
771
|
taskFunction: async () => {
|
|
@@ -443,9 +773,9 @@ services.forEach(service => {
|
|
|
443
773
|
if (!healthy) {
|
|
444
774
|
await alertOps(service);
|
|
445
775
|
}
|
|
446
|
-
}
|
|
776
|
+
},
|
|
447
777
|
});
|
|
448
|
-
|
|
778
|
+
|
|
449
779
|
healthMonitor.addAndScheduleTask(healthCheck, '*/1 * * * *'); // Every minute
|
|
450
780
|
});
|
|
451
781
|
```
|
|
@@ -476,7 +806,7 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
|
|
476
806
|
|
|
477
807
|
## License and Legal Information
|
|
478
808
|
|
|
479
|
-
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
809
|
+
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
480
810
|
|
|
481
811
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
482
812
|
|
|
@@ -491,4 +821,4 @@ Registered at District court Bremen HRB 35230 HB, Germany
|
|
|
491
821
|
|
|
492
822
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
|
493
823
|
|
|
494
|
-
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
|
824
|
+
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/taskbuffer',
|
|
6
|
-
version: '3.1.
|
|
6
|
+
version: '3.1.10',
|
|
7
7
|
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
|
8
8
|
}
|