@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.
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 +549 -0
  43. package/package.json +13 -12
  44. package/readme.md +429 -930
  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,611 @@
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.
31
+ ## ๐Ÿš€ Quick Start
43
32
 
44
- ### TaskDebounced
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 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 ๐Ÿ”ฌ
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
- ### Generic Task Functions
89
+ ### Task Buffering - Intelligent Request Management
114
90
 
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
-
155
- Tasks can accept setup values through generics, perfect for configuration:
156
103
 
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
108
  ```
186
109
 
187
- ### Type-Safe Task Chains
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
- Chain tasks with preserved type flow:
116
+ ### Task Chains - Sequential Workflows
117
+
118
+ Build complex workflows with automatic data flow:
190
119
 
191
120
  ```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();
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 filterTask = new Task<void>({
201
- name: 'FilterActive',
202
- taskFunction: async (users: UserData[]): Promise<UserData[]> => {
203
- return users.filter(user => user.isActive);
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 mapTask = new Task<void>({
208
- name: 'MapToProcessed',
209
- taskFunction: async (users: UserData[]): Promise<ProcessedUser[]> => {
210
- return users.map(transformUser);
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
- // Type safety flows through the chain
215
- const chain = new Taskchain({
216
- name: 'UserPipeline',
217
- taskArray: [fetchTask, filterTask, mapTask]
150
+ // Create and execute chain
151
+ const dataChain = new Taskchain({
152
+ name: 'DataPipeline',
153
+ tasks: [fetchTask, transformTask, saveTask]
218
154
  });
219
155
 
220
- const finalResult: ProcessedUser[] = await chain.trigger();
156
+ const savedCount = await dataChain.trigger();
157
+ console.log(`Saved ${savedCount} items`);
221
158
  ```
222
159
 
223
- ## Progress Tracking & Metadata ๐Ÿ“Š ๐Ÿ†•
160
+ ### Parallel Execution - Concurrent Processing
224
161
 
225
- TaskBuffer now provides comprehensive progress tracking and metadata collection, perfect for building dashboards and monitoring systems.
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
- 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,
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
- // 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`);
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
- ```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();
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
- ### TaskManager Enhanced Metadata
182
+ ### Debounced Tasks - Smart Trigger Coalescing
302
183
 
303
- The TaskManager now provides rich metadata for monitoring and dashboards:
184
+ Coalesce rapid triggers into a single execution after a quiet period:
304
185
 
305
186
  ```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
- });
187
+ import { TaskDebounced } from '@push.rocks/taskbuffer';
321
188
 
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}`);
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
- // Get upcoming executions
332
- const nextRuns = manager.getNextScheduledRuns(10);
333
- console.log('Next 10 scheduled executions:', nextRuns);
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
- ### Execute and Track Tasks
205
+ ### TaskManager - Centralized Orchestration
337
206
 
338
- Execute tasks with full lifecycle tracking and automatic cleanup:
207
+ Manage all your tasks from a single point:
339
208
 
340
209
  ```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
- }
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 with automatic cleanup and metadata collection
363
- const report = await manager.addExecuteRemoveTask(analyticsTask, {
242
+ // Execute and remove pattern
243
+ const report = await taskManager.addExecuteRemoveTask(temporaryTask, {
364
244
  trackProgress: true
365
245
  });
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
- });
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
- ### Frontend Integration Example
260
+ ## ๐ŸŽจ Web Component Dashboard
377
261
 
378
- Perfect for building real-time progress UIs:
262
+ Visualize your tasks in real-time with the included web component:
379
263
 
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
- });
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
- 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
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
- ### 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
- }
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
- // 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
477
- ```
293
+ ## ๐Ÿงฉ Advanced Patterns
478
294
 
479
- ### Advanced Buffer Strategies
295
+ ### Dynamic Task Routing
480
296
 
481
- #### 1. **Sliding Window Buffer**
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 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
- });
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
- return await api.call(request);
510
- },
511
- buffered: true,
512
- bufferMax: 10, // Max 10 queued requests
513
- execDelay: 1000 // 1 second between executions
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
- #### 3. **Priority Buffer** (Custom Implementation)
521
- Implement priority queuing with buffer management:
314
+ ### Task Pools
315
+
316
+ Create reusable task pools for load distribution:
522
317
 
523
318
  ```typescript
524
- class PriorityBufferedTask extends Task {
525
- private priorityQueue: Array<{data: any, priority: number}> = [];
319
+ class TaskPool {
320
+ private tasks: Task[] = [];
321
+ private currentIndex = 0;
526
322
 
527
- constructor(options) {
528
- super({
529
- ...options,
530
- taskFunction: async (item) => {
531
- // Process based on priority
532
- return await this.processByPriority(item);
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
- 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());
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
- ### 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
-
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
- ### Parallel Execution - Maximum Performance
345
+ ### Error Recovery & Retry
670
346
 
671
- Execute multiple independent tasks simultaneously:
347
+ Implement robust error handling:
672
348
 
673
349
  ```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,
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
- ### Scheduled Tasks with TaskManager
367
+ ### Task Composition
696
368
 
697
- Run tasks on a schedule using cron expressions:
369
+ Compose complex behaviors from simple tasks:
698
370
 
699
371
  ```typescript
700
- import { Task, TaskManager } from '@push.rocks/taskbuffer';
701
-
702
- const backupTask = new Task({
703
- name: 'DatabaseBackup',
372
+ const compositeTask = new Task({
373
+ name: 'CompositeOperation',
704
374
  steps: [
705
- { name: 'dump', description: 'Creating dump', percentage: 70 },
706
- { name: 'upload', description: 'Uploading to S3', percentage: 30 }
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
- backupTask.notifyStep('dump');
710
- await performBackup();
379
+ taskFunction: async function(data) {
380
+ this.notifyStep('validate');
381
+ const validated = await validationTask.trigger(data);
711
382
 
712
- backupTask.notifyStep('upload');
713
- await uploadToS3();
383
+ this.notifyStep('process');
384
+ const processed = await processingTask.trigger(validated);
714
385
 
715
- console.log(`Backup completed at ${new Date().toISOString()}`);
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
- ### Debounced Tasks - Smart Throttling
394
+ ## ๐Ÿ”ง Configuration
736
395
 
737
- Prevent task spam with intelligent debouncing:
396
+ ### Task Options
738
397
 
739
398
  ```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
- });
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
- ### One-Time Tasks - Initialize Once
758
-
759
- Ensure initialization code runs exactly once:
414
+ ### TaskManager Options
760
415
 
761
416
  ```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
- },
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
- ## Advanced Features ๐Ÿ”ฅ
424
+ ## ๐Ÿ“Š Monitoring & Observability
780
425
 
781
- ### Task Dependencies with Pre/Post Hooks
782
-
783
- Create sophisticated task relationships:
426
+ ### Task Events
784
427
 
785
428
  ```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
- });
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
- ### Task Runners - Distributed Execution
807
-
808
- The TaskRunner system enables distributed task execution across multiple workers:
435
+ ### Execution Metrics
809
436
 
810
437
  ```typescript
811
- import { TaskRunner } from '@push.rocks/taskbuffer';
812
-
813
- const runner = new TaskRunner({
814
- name: 'WorkerNode1',
815
- maxConcurrentTasks: 5,
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
- ## 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 ๐Ÿ›ก๏ธ
447
+ ## ๐Ÿงช Testing
924
448
 
925
449
  ```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
- }
450
+ import { expect, tap } from '@git.zone/tstest';
451
+ import { Task } from '@push.rocks/taskbuffer';
945
452
 
946
- // Or return default value
947
- return defaultValue;
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
- timeout: 5000, // Fail if takes longer than 5 seconds
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 Limiting with Progress
476
+ ### API Rate Limiter
957
477
 
958
478
  ```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
- },
479
+ const apiLimiter = new Task({
480
+ name: 'APIRateLimiter',
972
481
  buffered: true,
973
- bufferMax: 10, // 10 requests
974
- execDelay: 100, // Per 100ms = 100 req/s max
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 with Progress
493
+ ### Database Migration Pipeline
979
494
 
980
495
  ```typescript
981
496
  const migrationChain = new Taskchain({
982
497
  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();
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
- ### Microservice Health Monitoring Dashboard
517
+ ### Distributed Job Queue
1015
518
 
1016
519
  ```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
- });
520
+ const jobQueue = new TaskManager();
1042
521
 
1043
- healthMonitor.addAndScheduleTask(healthCheck, '*/1 * * * *'); // Every minute
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
- // 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
- });
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
- ## Testing ๐Ÿงช
557
+ ## ๐Ÿš€ Performance Tips
1064
558
 
1065
- ```typescript
1066
- import { expect, tap } from '@git.zone/tstest';
1067
- import { Task, TaskStep } from '@push.rocks/taskbuffer';
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
- 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
- });
565
+ ## ๐Ÿ” Debugging
1088
566
 
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
- });
567
+ Enable detailed logging:
1101
568
 
1102
- tap.start();
1103
- ```
569
+ ```typescript
570
+ import { logger } from '@push.rocks/smartlog';
1104
571
 
1105
- ## Support ๐Ÿ’ฌ
572
+ logger.enableConsole();
573
+ logger.level = 'debug';
574
+
575
+ // Tasks will now output detailed execution logs
576
+ ```
1106
577
 
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)
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