fix(tests): Update CI workflows, fix tests and refresh README/package metadata
This commit is contained in:
168
readme.md
168
readme.md
@@ -29,21 +29,27 @@ In the modern JavaScript ecosystem, managing asynchronous tasks efficiently is c
|
||||
## Core Concepts 🎓
|
||||
|
||||
### Task
|
||||
|
||||
The fundamental unit of work. A task wraps an asynchronous function and provides powerful execution control.
|
||||
|
||||
### Taskchain
|
||||
|
||||
Sequential task execution - tasks run one after another, with results passed along the chain.
|
||||
|
||||
### Taskparallel
|
||||
|
||||
Parallel task execution - multiple tasks run simultaneously for maximum performance.
|
||||
|
||||
### TaskManager
|
||||
|
||||
Centralized task scheduling and management using cron expressions.
|
||||
|
||||
### TaskDebounced
|
||||
|
||||
Debounced task execution - prevents rapid repeated executions, only running after a quiet period.
|
||||
|
||||
### TaskOnce
|
||||
|
||||
Singleton task execution - ensures a task runs exactly once, perfect for initialization routines.
|
||||
|
||||
## Quick Start 🏁
|
||||
@@ -59,7 +65,7 @@ const myTask = new Task({
|
||||
taskFunction: async () => {
|
||||
const data = await fetchData();
|
||||
return processData(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Execute the task
|
||||
@@ -78,7 +84,7 @@ const apiTask = new Task({
|
||||
},
|
||||
buffered: true,
|
||||
bufferMax: 3, // Maximum 3 concurrent executions
|
||||
execDelay: 1000 // Wait 1 second between executions
|
||||
execDelay: 1000, // Wait 1 second between executions
|
||||
});
|
||||
|
||||
// These will be automatically throttled
|
||||
@@ -99,18 +105,18 @@ const fetchTask = new Task({
|
||||
taskFunction: async () => {
|
||||
const response = await fetch('/api/data');
|
||||
return response.json();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const transformTask = new Task({
|
||||
name: 'TransformData',
|
||||
taskFunction: async (data) => {
|
||||
return data.map(item => ({
|
||||
return data.map((item) => ({
|
||||
...item,
|
||||
processed: true,
|
||||
timestamp: Date.now()
|
||||
timestamp: Date.now(),
|
||||
}));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const saveTask = new Task({
|
||||
@@ -118,12 +124,12 @@ const saveTask = new Task({
|
||||
taskFunction: async (transformedData) => {
|
||||
await database.bulkInsert(transformedData);
|
||||
return { saved: transformedData.length };
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const workflow = new Taskchain({
|
||||
name: 'DataPipeline',
|
||||
taskArray: [fetchTask, transformTask, saveTask]
|
||||
taskArray: [fetchTask, transformTask, saveTask],
|
||||
});
|
||||
|
||||
// Execute the entire chain
|
||||
@@ -138,18 +144,19 @@ Execute multiple independent tasks simultaneously:
|
||||
```typescript
|
||||
import { Task, Taskparallel } from '@push.rocks/taskbuffer';
|
||||
|
||||
const tasks = ['user', 'posts', 'comments'].map(resource =>
|
||||
new Task({
|
||||
name: `Fetch${resource}`,
|
||||
taskFunction: async () => {
|
||||
const data = await fetch(`/api/${resource}`);
|
||||
return data.json();
|
||||
}
|
||||
})
|
||||
const tasks = ['user', 'posts', 'comments'].map(
|
||||
(resource) =>
|
||||
new Task({
|
||||
name: `Fetch${resource}`,
|
||||
taskFunction: async () => {
|
||||
const data = await fetch(`/api/${resource}`);
|
||||
return data.json();
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const parallelFetch = new Taskparallel({
|
||||
taskArray: tasks
|
||||
taskArray: tasks,
|
||||
});
|
||||
|
||||
// All tasks execute simultaneously
|
||||
@@ -168,7 +175,7 @@ const backupTask = new Task({
|
||||
taskFunction: async () => {
|
||||
await performBackup();
|
||||
console.log(`Backup completed at ${new Date().toISOString()}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const manager = new TaskManager();
|
||||
@@ -197,7 +204,7 @@ const saveTask = new TaskDebounced({
|
||||
await saveToDatabase(content);
|
||||
console.log('Content saved');
|
||||
},
|
||||
debounceTimeInMillis: 2000 // Wait 2 seconds of inactivity
|
||||
debounceTimeInMillis: 2000, // Wait 2 seconds of inactivity
|
||||
});
|
||||
|
||||
// Rapid calls will be debounced
|
||||
@@ -220,7 +227,7 @@ const initTask = new TaskOnce({
|
||||
await cache.initialize();
|
||||
await loadConfiguration();
|
||||
console.log('System initialized');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Safe to call multiple times - only runs once
|
||||
@@ -242,7 +249,7 @@ const validationTask = new Task({
|
||||
throw new Error('Validation failed');
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const mainTask = new Task({
|
||||
@@ -250,8 +257,8 @@ const mainTask = new Task({
|
||||
taskFunction: async (data) => {
|
||||
return await complexProcessing(data);
|
||||
},
|
||||
preTask: validationTask, // Runs before main task
|
||||
afterTask: cleanupTask // Runs after main task
|
||||
preTask: validationTask, // Runs before main task
|
||||
afterTask: cleanupTask, // Runs after main task
|
||||
});
|
||||
```
|
||||
|
||||
@@ -264,7 +271,7 @@ import { TaskRunner } from '@push.rocks/taskbuffer';
|
||||
|
||||
const runner = new TaskRunner({
|
||||
name: 'WorkerNode1',
|
||||
maxConcurrentTasks: 5
|
||||
maxConcurrentTasks: 5,
|
||||
});
|
||||
|
||||
// Register tasks this runner can handle
|
||||
@@ -282,11 +289,13 @@ Fine-tune concurrent execution behavior:
|
||||
```typescript
|
||||
const task = new Task({
|
||||
name: 'ResourceIntensive',
|
||||
taskFunction: async () => { /* ... */ },
|
||||
taskFunction: async () => {
|
||||
/* ... */
|
||||
},
|
||||
buffered: true,
|
||||
bufferMax: 5, // Max 5 concurrent
|
||||
execDelay: 100, // 100ms between starts
|
||||
timeout: 30000 // 30 second timeout
|
||||
bufferMax: 5, // Max 5 concurrent
|
||||
execDelay: 100, // 100ms between starts
|
||||
timeout: 30000, // 30 second timeout
|
||||
});
|
||||
```
|
||||
|
||||
@@ -297,14 +306,18 @@ TaskBuffer automatically detects and prevents circular dependencies:
|
||||
```typescript
|
||||
const taskA = new Task({
|
||||
name: 'TaskA',
|
||||
taskFunction: async () => { /* ... */ },
|
||||
preTask: taskB // This would create a cycle
|
||||
taskFunction: async () => {
|
||||
/* ... */
|
||||
},
|
||||
preTask: taskB, // This would create a cycle
|
||||
});
|
||||
|
||||
const taskB = new Task({
|
||||
name: 'TaskB',
|
||||
taskFunction: async () => { /* ... */ },
|
||||
preTask: taskA // Circular dependency detected!
|
||||
taskFunction: async () => {
|
||||
/* ... */
|
||||
},
|
||||
preTask: taskA, // Circular dependency detected!
|
||||
});
|
||||
```
|
||||
|
||||
@@ -314,20 +327,21 @@ Create tasks on-the-fly based on runtime conditions:
|
||||
|
||||
```typescript
|
||||
const dynamicWorkflow = async (config: Config) => {
|
||||
const tasks = config.steps.map(step =>
|
||||
new Task({
|
||||
name: step.name,
|
||||
taskFunction: async (input) => {
|
||||
return await processStep(step, input);
|
||||
}
|
||||
})
|
||||
const tasks = config.steps.map(
|
||||
(step) =>
|
||||
new Task({
|
||||
name: step.name,
|
||||
taskFunction: async (input) => {
|
||||
return await processStep(step, input);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
const chain = new Taskchain({
|
||||
name: 'DynamicWorkflow',
|
||||
taskArray: tasks
|
||||
taskArray: tasks,
|
||||
});
|
||||
|
||||
|
||||
return await chain.trigger();
|
||||
};
|
||||
```
|
||||
@@ -336,35 +350,35 @@ const dynamicWorkflow = async (config: Config) => {
|
||||
|
||||
### Task Options
|
||||
|
||||
| Option | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `name` | `string` | Unique identifier for the task |
|
||||
| `taskFunction` | `Function` | Async function to execute |
|
||||
| `buffered` | `boolean` | Enable buffer management |
|
||||
| `bufferMax` | `number` | Maximum concurrent executions |
|
||||
| `execDelay` | `number` | Delay between executions (ms) |
|
||||
| `timeout` | `number` | Task timeout (ms) |
|
||||
| `preTask` | `Task` | Task to run before |
|
||||
| `afterTask` | `Task` | Task to run after |
|
||||
| Option | Type | Description |
|
||||
| -------------- | ---------- | ------------------------------ |
|
||||
| `name` | `string` | Unique identifier for the task |
|
||||
| `taskFunction` | `Function` | Async function to execute |
|
||||
| `buffered` | `boolean` | Enable buffer management |
|
||||
| `bufferMax` | `number` | Maximum concurrent executions |
|
||||
| `execDelay` | `number` | Delay between executions (ms) |
|
||||
| `timeout` | `number` | Task timeout (ms) |
|
||||
| `preTask` | `Task` | Task to run before |
|
||||
| `afterTask` | `Task` | Task to run after |
|
||||
|
||||
### TaskManager Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `addTask(task, cronExpression)` | Add and schedule a task |
|
||||
| `removeTask(taskName)` | Remove a scheduled task |
|
||||
| `start()` | Start the scheduler |
|
||||
| `stop()` | Stop the scheduler |
|
||||
| `getStats()` | Get execution statistics |
|
||||
| Method | Description |
|
||||
| ------------------------------- | ------------------------ |
|
||||
| `addTask(task, cronExpression)` | Add and schedule a task |
|
||||
| `removeTask(taskName)` | Remove a scheduled task |
|
||||
| `start()` | Start the scheduler |
|
||||
| `stop()` | Stop the scheduler |
|
||||
| `getStats()` | Get execution statistics |
|
||||
|
||||
### Taskchain Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `addTask(task)` | Add task to chain |
|
||||
| `removeTask(taskName)` | Remove task from chain |
|
||||
| `trigger(initialValue)` | Execute the chain |
|
||||
| `reset()` | Reset chain state |
|
||||
| Method | Description |
|
||||
| ----------------------- | ---------------------- |
|
||||
| `addTask(task)` | Add task to chain |
|
||||
| `removeTask(taskName)` | Remove task from chain |
|
||||
| `trigger(initialValue)` | Execute the chain |
|
||||
| `reset()` | Reset chain state |
|
||||
|
||||
## Performance Tips 🏎️
|
||||
|
||||
@@ -385,17 +399,17 @@ const robustTask = new Task({
|
||||
} catch (error) {
|
||||
// Log error
|
||||
console.error(`Task failed: ${error.message}`);
|
||||
|
||||
|
||||
// Optionally retry
|
||||
if (error.retryable) {
|
||||
return await riskyOperation(input);
|
||||
}
|
||||
|
||||
|
||||
// Or return default value
|
||||
return defaultValue;
|
||||
}
|
||||
},
|
||||
timeout: 5000 // Fail if takes longer than 5 seconds
|
||||
timeout: 5000, // Fail if takes longer than 5 seconds
|
||||
});
|
||||
```
|
||||
|
||||
@@ -410,8 +424,8 @@ const apiClient = new Task({
|
||||
return await fetch(`https://api.example.com${endpoint}`);
|
||||
},
|
||||
buffered: true,
|
||||
bufferMax: 10, // 10 requests
|
||||
execDelay: 100 // Per 100ms = 100 req/s max
|
||||
bufferMax: 10, // 10 requests
|
||||
execDelay: 100, // Per 100ms = 100 req/s max
|
||||
});
|
||||
```
|
||||
|
||||
@@ -425,8 +439,8 @@ const migrationChain = new Taskchain({
|
||||
schemaUpdateTask,
|
||||
dataTransformTask,
|
||||
validationTask,
|
||||
cleanupTask
|
||||
]
|
||||
cleanupTask,
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
@@ -435,7 +449,7 @@ const migrationChain = new Taskchain({
|
||||
```typescript
|
||||
const healthMonitor = new TaskManager();
|
||||
|
||||
services.forEach(service => {
|
||||
services.forEach((service) => {
|
||||
const healthCheck = new Task({
|
||||
name: `HealthCheck:${service.name}`,
|
||||
taskFunction: async () => {
|
||||
@@ -443,9 +457,9 @@ services.forEach(service => {
|
||||
if (!healthy) {
|
||||
await alertOps(service);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
healthMonitor.addAndScheduleTask(healthCheck, '*/1 * * * *'); // Every minute
|
||||
});
|
||||
```
|
||||
@@ -476,7 +490,7 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
@@ -491,4 +505,4 @@ Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
Reference in New Issue
Block a user