@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.
Files changed (49) hide show
  1. package/LICENSE +1 -1
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/ts/index.d.ts +13 -0
  4. package/dist_ts_web/ts/index.js +12 -0
  5. package/dist_ts_web/ts/taskbuffer.classes.bufferrunner.d.ts +8 -0
  6. package/dist_ts_web/ts/taskbuffer.classes.bufferrunner.js +28 -0
  7. package/dist_ts_web/ts/taskbuffer.classes.cyclecounter.d.ts +13 -0
  8. package/dist_ts_web/ts/taskbuffer.classes.cyclecounter.js +31 -0
  9. package/dist_ts_web/ts/taskbuffer.classes.distributedcoordinator.d.ts +27 -0
  10. package/dist_ts_web/ts/taskbuffer.classes.distributedcoordinator.js +5 -0
  11. package/dist_ts_web/ts/taskbuffer.classes.task.d.ts +86 -0
  12. package/dist_ts_web/ts/taskbuffer.classes.task.js +257 -0
  13. package/dist_ts_web/ts/taskbuffer.classes.taskchain.d.ts +14 -0
  14. package/dist_ts_web/ts/taskbuffer.classes.taskchain.js +51 -0
  15. package/dist_ts_web/ts/taskbuffer.classes.taskdebounced.d.ts +10 -0
  16. package/dist_ts_web/ts/taskbuffer.classes.taskdebounced.js +20 -0
  17. package/dist_ts_web/ts/taskbuffer.classes.taskmanager.d.ts +49 -0
  18. package/dist_ts_web/ts/taskbuffer.classes.taskmanager.js +208 -0
  19. package/dist_ts_web/ts/taskbuffer.classes.taskonce.d.ts +11 -0
  20. package/dist_ts_web/ts/taskbuffer.classes.taskonce.js +20 -0
  21. package/dist_ts_web/ts/taskbuffer.classes.taskparallel.d.ts +7 -0
  22. package/dist_ts_web/ts/taskbuffer.classes.taskparallel.js +23 -0
  23. package/dist_ts_web/ts/taskbuffer.classes.taskrunner.d.ts +30 -0
  24. package/dist_ts_web/ts/taskbuffer.classes.taskrunner.js +54 -0
  25. package/dist_ts_web/ts/taskbuffer.classes.taskstep.d.ts +27 -0
  26. package/dist_ts_web/ts/taskbuffer.classes.taskstep.js +37 -0
  27. package/dist_ts_web/ts/taskbuffer.interfaces.d.ts +36 -0
  28. package/dist_ts_web/ts/taskbuffer.interfaces.js +2 -0
  29. package/dist_ts_web/ts/taskbuffer.logging.d.ts +2 -0
  30. package/dist_ts_web/ts/taskbuffer.logging.js +3 -0
  31. package/dist_ts_web/ts/taskbuffer.plugins.d.ts +8 -0
  32. package/dist_ts_web/ts/taskbuffer.plugins.js +9 -0
  33. package/dist_ts_web/ts_web/00_commitinfo_data.d.ts +8 -0
  34. package/dist_ts_web/ts_web/00_commitinfo_data.js +9 -0
  35. package/dist_ts_web/ts_web/demorunner.d.ts +1 -0
  36. package/dist_ts_web/ts_web/demorunner.js +33 -0
  37. package/dist_ts_web/ts_web/elements/taskbuffer-dashboard.demo.d.ts +2 -0
  38. package/dist_ts_web/ts_web/elements/taskbuffer-dashboard.demo.js +285 -0
  39. package/dist_ts_web/ts_web/index.d.ts +2 -0
  40. package/dist_ts_web/ts_web/index.js +3 -0
  41. package/dist_ts_web/ts_web/taskbuffer-dashboard.d.ts +24 -0
  42. package/dist_ts_web/ts_web/taskbuffer-dashboard.js +557 -0
  43. package/package.json +5 -4
  44. package/readme.md +412 -938
  45. package/ts/00_commitinfo_data.ts +1 -1
  46. package/ts_web/00_commitinfo_data.ts +1 -1
  47. package/ts_web/elements/taskbuffer-dashboard.demo.ts +311 -0
  48. package/ts_web/index.ts +12 -0
  49. package/ts_web/taskbuffer-dashboard.ts +541 -0
package/readme.md CHANGED
@@ -1,1112 +1,586 @@
1
1
  # @push.rocks/taskbuffer ๐Ÿš€
2
2
 
3
- A **powerful**, **flexible**, and **TypeScript-first** task management library for orchestrating asynchronous operations with style. From simple task execution to complex distributed workflows with real-time progress tracking, taskbuffer has got you covered.
3
+ > **Modern TypeScript task orchestration with smart buffering, scheduling, and real-time progress tracking**
4
4
 
5
- ## Install ๐Ÿ“ฆ
5
+ [![npm version](https://img.shields.io/npm/v/@push.rocks/taskbuffer.svg)](https://www.npmjs.com/package/@push.rocks/taskbuffer)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
8
 
7
- ```bash
8
- npm install @push.rocks/taskbuffer --save
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
- Or with **pnpm** (recommended):
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
- ## Why taskbuffer? ๐Ÿค”
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
- ### 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 myTask = new Task({
62
- name: 'DataProcessor',
63
- taskFunction: async () => {
64
- const data = await fetchData();
65
- return processData(data);
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 myTask.trigger();
49
+ const result = await dataProcessor.trigger('my-data');
50
+ console.log(result); // "Processed: my-data"
71
51
  ```
72
52
 
73
- ### Task with Progress Steps ๐Ÿ†•
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 dataProcessingTask = new Task({
79
- name: 'DataProcessor',
56
+ const deploymentTask = new Task({
57
+ name: 'DeployApplication',
80
58
  steps: [
81
- { name: 'validate', description: 'Validating input data', percentage: 15 },
82
- { name: 'fetch', description: 'Fetching external resources', percentage: 25 },
83
- { name: 'transform', description: 'Transforming data', percentage: 35 },
84
- { name: 'save', description: 'Saving to database', percentage: 25 }
85
- ] as const, // Use 'as const' for full type safety
86
- taskFunction: async (inputData) => {
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
- dataProcessingTask.notifyStep('validate');
89
- const validated = await validateData(inputData);
66
+ this.notifyStep('build');
67
+ await buildApplication();
90
68
 
91
- dataProcessingTask.notifyStep('fetch');
92
- const external = await fetchExternalData();
69
+ this.notifyStep('test');
70
+ await runTests();
93
71
 
94
- dataProcessingTask.notifyStep('transform');
95
- const transformed = await transformData(validated, external);
72
+ this.notifyStep('deploy');
73
+ await deployToServer();
96
74
 
97
- dataProcessingTask.notifyStep('save');
98
- const result = await saveToDatabase(transformed);
75
+ this.notifyStep('verify');
76
+ await verifyDeployment();
99
77
 
100
- return result;
78
+ return 'Deployment successful!';
101
79
  }
102
80
  });
103
81
 
104
- // Monitor progress in real-time
105
- const result = await dataProcessingTask.trigger();
106
- console.log(`Final progress: ${dataProcessingTask.getProgress()}%`); // 100%
82
+ // Monitor progress
83
+ console.log(deploymentTask.getProgress()); // 0-100
84
+ console.log(deploymentTask.getStepsMetadata()); // Detailed step info
107
85
  ```
108
86
 
109
- ## TypeScript Generics Support ๐Ÿ”ฌ
87
+ ## ๐ŸŽฏ Core Concepts
110
88
 
111
- TaskBuffer leverages TypeScript's powerful generics system for complete type safety across your task chains and workflows.
89
+ ### Task Buffering - Intelligent Request Management
112
90
 
113
- ### Generic Task Functions
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
- import { Task, ITaskFunction } from '@push.rocks/taskbuffer';
119
-
120
- // Define typed interfaces
121
- interface UserData {
122
- id: string;
123
- name: string;
124
- email: string;
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
- Tasks can accept setup values through generics, perfect for configuration:
156
-
157
- ```typescript
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
- ## Progress Tracking & Metadata ๐Ÿ“Š ๐Ÿ†•
224
-
225
- TaskBuffer now provides comprehensive progress tracking and metadata collection, perfect for building dashboards and monitoring systems.
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
- ### Step-by-Step Progress
116
+ ### Task Chains - Sequential Workflows
228
117
 
229
- Define weighted steps for accurate progress calculation:
118
+ Build complex workflows with automatic data flow:
230
119
 
231
120
  ```typescript
232
- const migrationTask = new Task({
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,
121
+ import { Task, Taskchain } from '@push.rocks/taskbuffer';
122
+
123
+ const fetchTask = new Task({
124
+ name: 'FetchData',
240
125
  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%
126
+ const response = await fetch('/api/data');
127
+ return response.json();
256
128
  }
257
129
  });
258
130
 
259
- // Get detailed step information
260
- const steps = migrationTask.getStepsMetadata();
261
- steps.forEach(step => {
262
- console.log(`${step.name}: ${step.status} (${step.percentage}%)`);
263
- if (step.duration) {
264
- console.log(` Duration: ${step.duration}ms`);
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
- Get comprehensive metadata about task execution:
272
-
273
- ```typescript
274
- const task = new Task({
275
- name: 'DataProcessor',
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
- // 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
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
- ### TaskManager Enhanced Metadata
160
+ ### Parallel Execution - Concurrent Processing
302
161
 
303
- The TaskManager now provides rich metadata for monitoring and dashboards:
162
+ Execute multiple tasks simultaneously:
304
163
 
305
164
  ```typescript
306
- const manager = new TaskManager();
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
- // Get scheduled tasks with next run times
323
- const scheduledTasks = manager.getScheduledTasks();
324
- scheduledTasks.forEach(task => {
325
- console.log(`${task.name}: Next run at ${task.nextRun}`);
326
- if (task.steps) {
327
- console.log(` Steps: ${task.steps.length}`);
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
- // Get upcoming executions
332
- const nextRuns = manager.getNextScheduledRuns(10);
333
- console.log('Next 10 scheduled executions:', nextRuns);
177
+ // All tasks execute concurrently
178
+ const results = await parallel.trigger(notificationData);
179
+ // results = [emailResult, smsResult, pushResult, webhookResult]
334
180
  ```
335
181
 
336
- ### Execute and Track Tasks
182
+ ### TaskManager - Centralized Orchestration
337
183
 
338
- Execute tasks with full lifecycle tracking and automatic cleanup:
184
+ Manage all your tasks from a single point:
339
185
 
340
186
  ```typescript
341
- const manager = new TaskManager();
342
-
343
- const analyticsTask = new Task({
344
- name: 'Analytics',
345
- steps: [
346
- { name: 'collect', description: 'Collecting metrics', percentage: 30 },
347
- { name: 'analyze', description: 'Analyzing data', percentage: 50 },
348
- { name: 'report', description: 'Generating report', percentage: 20 }
349
- ] as const,
350
- taskFunction: async () => {
351
- analyticsTask.notifyStep('collect');
352
- const metrics = await collectMetrics();
353
-
354
- analyticsTask.notifyStep('analyze');
355
- const analysis = await analyzeData(metrics);
356
-
357
- analyticsTask.notifyStep('report');
358
- return await generateReport(analysis);
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 with automatic cleanup and metadata collection
363
- const report = await manager.addExecuteRemoveTask(analyticsTask, {
219
+ // Execute and remove pattern
220
+ const report = await taskManager.addExecuteRemoveTask(temporaryTask, {
364
221
  trackProgress: true
365
222
  });
366
-
367
- console.log('Execution Report:', {
368
- taskName: report.taskName,
369
- duration: report.duration,
370
- stepsCompleted: report.stepsCompleted,
371
- finalProgress: report.progress,
372
- result: report.result
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
- ### Frontend Integration Example
237
+ ## ๐ŸŽจ Web Component Dashboard
377
238
 
378
- Perfect for building real-time progress UIs:
239
+ Visualize your tasks in real-time with the included web component:
379
240
 
380
- ```typescript
381
- // WebSocket server for real-time updates
382
- io.on('connection', (socket) => {
383
- socket.on('startTask', async (taskId) => {
384
- const task = new Task({
385
- name: taskId,
386
- steps: [
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
- await task.trigger();
416
- socket.emit('complete', task.getMetadata());
417
- });
418
- });
419
- ```
420
-
421
- ## Buffer Behavior Deep Dive ๐ŸŒŠ
422
-
423
- The buffer system in TaskBuffer provides intelligent control over concurrent executions, preventing system overload while maximizing throughput.
424
-
425
- ### How Buffering Works
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
- ### Advanced Buffer Strategies
480
-
481
- #### 1. **Sliding Window Buffer**
482
- Perfect for real-time data processing where only recent items matter:
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
- ```typescript
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
- // 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
- ```
272
+ ### Dynamic Task Routing
501
273
 
502
- #### 2. **Throttled Buffer**
503
- Combine buffering with execution delays for rate limiting:
274
+ Route tasks based on conditions:
504
275
 
505
276
  ```typescript
506
- const apiRateLimiter = new Task({
507
- name: 'RateLimitedAPI',
277
+ const routerTask = new Task({
278
+ name: 'Router',
508
279
  taskFunction: async (request) => {
509
- return await api.call(request);
510
- },
511
- buffered: true,
512
- bufferMax: 10, // Max 10 queued requests
513
- execDelay: 1000 // 1 second between executions
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
- #### 3. **Priority Buffer** (Custom Implementation)
521
- Implement priority queuing with buffer management:
291
+ ### Task Pools
292
+
293
+ Create reusable task pools for load distribution:
522
294
 
523
295
  ```typescript
524
- class PriorityBufferedTask extends Task {
525
- private priorityQueue: Array<{data: any, priority: number}> = [];
296
+ class TaskPool {
297
+ private tasks: Task[] = [];
298
+ private currentIndex = 0;
526
299
 
527
- constructor(options) {
528
- super({
529
- ...options,
530
- taskFunction: async (item) => {
531
- // Process based on priority
532
- return await this.processByPriority(item);
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
- triggerWithPriority(data: any, priority: number) {
538
- if (this.priorityQueue.length >= this.bufferMax) {
539
- // Remove lowest priority item if buffer full
540
- this.priorityQueue.sort((a, b) => b.priority - a.priority);
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 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],
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
- ### Parallel Execution - Maximum Performance
322
+ ### Error Recovery & Retry
670
323
 
671
- Execute multiple independent tasks simultaneously:
324
+ Implement robust error handling:
672
325
 
673
326
  ```typescript
674
- import { Task, Taskparallel } from '@push.rocks/taskbuffer';
675
-
676
- const tasks = ['user', 'posts', 'comments'].map(
677
- (resource) =>
678
- new Task({
679
- name: `Fetch${resource}`,
680
- taskFunction: async () => {
681
- const data = await fetch(`/api/${resource}`);
682
- return data.json();
683
- },
684
- }),
685
- );
686
-
687
- const parallelFetch = new Taskparallel({
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
- ### Scheduled Tasks with TaskManager
344
+ ### Task Composition
696
345
 
697
- Run tasks on a schedule using cron expressions:
346
+ Compose complex behaviors from simple tasks:
698
347
 
699
348
  ```typescript
700
- import { Task, TaskManager } from '@push.rocks/taskbuffer';
701
-
702
- const backupTask = new Task({
703
- name: 'DatabaseBackup',
349
+ const compositeTask = new Task({
350
+ name: 'CompositeOperation',
704
351
  steps: [
705
- { name: 'dump', description: 'Creating dump', percentage: 70 },
706
- { name: 'upload', description: 'Uploading to S3', percentage: 30 }
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
- backupTask.notifyStep('dump');
710
- await performBackup();
356
+ taskFunction: async function(data) {
357
+ this.notifyStep('validate');
358
+ const validated = await validationTask.trigger(data);
711
359
 
712
- backupTask.notifyStep('upload');
713
- await uploadToS3();
360
+ this.notifyStep('process');
361
+ const processed = await processingTask.trigger(validated);
714
362
 
715
- console.log(`Backup completed at ${new Date().toISOString()}`);
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
- ### Debounced Tasks - Smart Throttling
371
+ ## ๐Ÿ”ง Configuration
736
372
 
737
- Prevent task spam with intelligent debouncing:
373
+ ### Task Options
738
374
 
739
375
  ```typescript
740
- import { TaskDebounced } from '@push.rocks/taskbuffer';
741
-
742
- const saveTask = new TaskDebounced({
743
- name: 'AutoSave',
744
- taskFunction: async (content: string) => {
745
- await saveToDatabase(content);
746
- console.log('Content saved');
747
- },
748
- debounceTimeInMillis: 2000, // Wait 2 seconds of inactivity
749
- });
750
-
751
- // Rapid calls will be debounced
752
- input.addEventListener('input', (e) => {
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
- ### One-Time Tasks - Initialize Once
758
-
759
- Ensure initialization code runs exactly once:
391
+ ### TaskManager Options
760
392
 
761
393
  ```typescript
762
- import { TaskOnce } from '@push.rocks/taskbuffer';
763
-
764
- const initTask = new TaskOnce({
765
- name: 'SystemInitialization',
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
- ## Advanced Features ๐Ÿ”ฅ
780
-
781
- ### Task Dependencies with Pre/Post Hooks
401
+ ## ๐Ÿ“Š Monitoring & Observability
782
402
 
783
- Create sophisticated task relationships:
403
+ ### Task Events
784
404
 
785
405
  ```typescript
786
- const validationTask = new Task({
787
- name: 'ValidateInput',
788
- taskFunction: async (data) => {
789
- if (!isValid(data)) {
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
- ### Task Runners - Distributed Execution
807
-
808
- The TaskRunner system enables distributed task execution across multiple workers:
412
+ ### Execution Metrics
809
413
 
810
414
  ```typescript
811
- import { TaskRunner } from '@push.rocks/taskbuffer';
812
-
813
- const runner = new TaskRunner({
814
- name: 'WorkerNode1',
815
- maxConcurrentTasks: 5,
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
- ## API Reference ๐Ÿ“š
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
- const robustTask = new Task({
927
- name: 'RobustOperation',
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
- // Or return default value
947
- return defaultValue;
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
- timeout: 5000, // Fail if takes longer than 5 seconds
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 Limiting with Progress
453
+ ### API Rate Limiter
957
454
 
958
455
  ```typescript
959
- const apiClient = new Task({
960
- name: 'RateLimitedAPI',
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, // 10 requests
974
- execDelay: 100, // Per 100ms = 100 req/s max
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 with Progress
470
+ ### Database Migration Pipeline
979
471
 
980
472
  ```typescript
981
473
  const migrationChain = new Taskchain({
982
474
  name: 'DatabaseMigration',
983
- taskArray: [
984
- new Task({
985
- name: 'Backup',
986
- steps: [{ name: 'backup', description: 'Creating backup', percentage: 100 }] as const,
987
- taskFunction: async () => {
988
- backupTask.notifyStep('backup');
989
- return await createBackup();
990
- }
991
- }),
992
- new Task({
993
- name: 'SchemaUpdate',
994
- steps: [
995
- { name: 'analyze', description: 'Analyzing changes', percentage: 30 },
996
- { name: 'apply', description: 'Applying migrations', percentage: 70 }
997
- ] as const,
998
- taskFunction: async () => {
999
- schemaTask.notifyStep('analyze');
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
- ### Microservice Health Monitoring Dashboard
494
+ ### Distributed Job Queue
1015
495
 
1016
496
  ```typescript
1017
- const healthMonitor = new TaskManager();
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
- healthMonitor.addAndScheduleTask(healthCheck, '*/1 * * * *'); // Every minute
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
- // Dashboard endpoint
1047
- app.get('/api/health/dashboard', (req, res) => {
1048
- const metadata = healthMonitor.getAllTasksMetadata();
1049
- res.json({
1050
- services: metadata.map(task => ({
1051
- name: task.name.replace('HealthCheck:', ''),
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
- ## Testing ๐Ÿงช
534
+ ## ๐Ÿš€ Performance Tips
1064
535
 
1065
- ```typescript
1066
- import { expect, tap } from '@git.zone/tstest';
1067
- import { Task, TaskStep } from '@push.rocks/taskbuffer';
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
- tap.test('should track task progress through steps', async () => {
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
- tap.test('should collect execution metadata', async () => {
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
- tap.start();
1103
- ```
546
+ ```typescript
547
+ import { logger } from '@push.rocks/smartlog';
1104
548
 
1105
- ## Support ๐Ÿ’ฌ
549
+ logger.enableConsole();
550
+ logger.level = 'debug';
551
+
552
+ // Tasks will now output detailed execution logs
553
+ ```
1106
554
 
1107
- - ๐Ÿ“ง Email: [hello@task.vc](mailto:hello@task.vc)
1108
- - ๐Ÿ› Issues: [GitHub Issues](https://github.com/push-rocks/taskbuffer/issues)
1109
- - ๐Ÿ“– Docs: [Documentation](https://code.foss.global/push.rocks/taskbuffer)
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