@supergrowthai/tq 1.0.1-canary.a2ffe03
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +426 -0
- package/dist/core/base/interfaces.d.ts +1 -0
- package/dist/core/base/interfaces.js +2 -0
- package/dist/core/base/interfaces.js.map +1 -0
- package/dist/core/base/interfaces.mjs +2 -0
- package/dist/core/base/interfaces.mjs.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1985 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1985 -0
- package/dist/index.mjs.map +1 -0
- package/dist/src/adapters/CronTasksAdapter.d.ts +34 -0
- package/dist/src/adapters/IDatabaseAdapter.d.ts +57 -0
- package/dist/src/adapters/MongoDbAdapter.d.ts +33 -0
- package/dist/src/adapters/database-adapter.d.ts +7 -0
- package/dist/src/adapters/index.d.ts +5 -0
- package/dist/src/core/actions/Actions.d.ts +33 -0
- package/dist/src/core/actions/AsyncActions.d.ts +17 -0
- package/dist/src/core/async/AsyncTaskManager.d.ts +19 -0
- package/dist/src/core/base/interfaces.d.ts +35 -0
- package/dist/src/core/environment.d.ts +6 -0
- package/dist/src/core/task-handler.d.ts +19 -0
- package/dist/src/core/task-runner.d.ts +19 -0
- package/dist/src/core/task-store.d.ts +74 -0
- package/dist/src/index.d.ts +46 -0
- package/dist/src/task-registry.d.ts +4 -0
- package/dist/src/types.d.ts +2 -0
- package/dist/src/utils/task-id-gen.d.ts +3 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +7 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +101 -0
package/README.md
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# @supergrowthai/tq
|
|
2
|
+
|
|
3
|
+
A task queue management library with multiple executor types and async task handling. Built on top of @supergrowthai/mq
|
|
4
|
+
for flexible message queue backends.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Multiple Executor Types**: Single task (parallel/non-parallel) and multi-task executors
|
|
9
|
+
- **Async Task Management**: Handle long-running tasks with configurable timeouts
|
|
10
|
+
- **Type-Safe**: Full TypeScript support with generic task types
|
|
11
|
+
- **Queue Integration**: Works with any message queue backend via @supergrowthai/mq
|
|
12
|
+
- **Flexible Registration**: Register task executors for different queue types
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @supergrowthai/tq @supergrowthai/mq
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Basic Usage
|
|
21
|
+
|
|
22
|
+
### Setting Up Task Executors
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import taskQueue from '@supergrowthai/tq';
|
|
26
|
+
import messageQueue from '@supergrowthai/mq';
|
|
27
|
+
import {ISingleTaskNonParallel} from '@supergrowthai/tq/core/base/interfaces';
|
|
28
|
+
|
|
29
|
+
// Define a simple task executor
|
|
30
|
+
const emailExecutor: ISingleTaskNonParallel<EmailTaskData> = {
|
|
31
|
+
multiple: false,
|
|
32
|
+
parallel: false,
|
|
33
|
+
default_retries: 3,
|
|
34
|
+
store_on_failure: true,
|
|
35
|
+
|
|
36
|
+
async onTask(task, actions) {
|
|
37
|
+
try {
|
|
38
|
+
await sendEmail(task.data.to, task.data.subject, task.data.body);
|
|
39
|
+
actions.success(task);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('Failed to send email:', error);
|
|
42
|
+
actions.fail(task);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Register the executor
|
|
48
|
+
taskQueue.register(
|
|
49
|
+
messageQueue, // Message queue instance
|
|
50
|
+
'email-queue', // Queue name
|
|
51
|
+
'send-email', // Task type
|
|
52
|
+
emailExecutor // Executor implementation
|
|
53
|
+
);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Task Types and Interfaces
|
|
57
|
+
|
|
58
|
+
#### Single Task Non-Parallel Executor
|
|
59
|
+
|
|
60
|
+
For tasks that should be processed one at a time:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import {ISingleTaskNonParallel} from '@supergrowthai/tq/core/base/interfaces';
|
|
64
|
+
|
|
65
|
+
const reportExecutor: ISingleTaskNonParallel<ReportData> = {
|
|
66
|
+
multiple: false,
|
|
67
|
+
parallel: false,
|
|
68
|
+
default_retries: 2,
|
|
69
|
+
store_on_failure: true,
|
|
70
|
+
|
|
71
|
+
async onTask(task, actions) {
|
|
72
|
+
console.log(`Generating report: ${task.data.reportId}`);
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const report = await generateReport(task.data);
|
|
76
|
+
actions.success(task);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
actions.fail(task);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Single Task Parallel Executor
|
|
85
|
+
|
|
86
|
+
For tasks that can be processed in parallel batches:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import {ISingleTaskParallel} from '@supergrowthai/tq/core/base/interfaces';
|
|
90
|
+
|
|
91
|
+
const imageProcessorExecutor: ISingleTaskParallel<ImageData> = {
|
|
92
|
+
multiple: false,
|
|
93
|
+
parallel: true,
|
|
94
|
+
chunkSize: 5, // Process 5 images at a time
|
|
95
|
+
default_retries: 3,
|
|
96
|
+
store_on_failure: true,
|
|
97
|
+
|
|
98
|
+
async onTask(task, actions) {
|
|
99
|
+
try {
|
|
100
|
+
await processImage(task.data.imageUrl, task.data.filters);
|
|
101
|
+
actions.success(task);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error('Image processing failed:', error);
|
|
104
|
+
actions.fail(task);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Multi-Task Executor
|
|
111
|
+
|
|
112
|
+
For processing multiple tasks together as a batch:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import {IMultiTaskExecutor} from '@supergrowthai/tq/core/base/interfaces';
|
|
116
|
+
|
|
117
|
+
const batchProcessorExecutor: IMultiTaskExecutor<BatchData> = {
|
|
118
|
+
multiple: true,
|
|
119
|
+
default_retries: 2,
|
|
120
|
+
store_on_failure: true,
|
|
121
|
+
|
|
122
|
+
async onTasks(tasks, actions) {
|
|
123
|
+
console.log(`Processing batch of ${tasks.length} tasks`);
|
|
124
|
+
|
|
125
|
+
for (const task of tasks) {
|
|
126
|
+
try {
|
|
127
|
+
await processBatchItem(task.data);
|
|
128
|
+
actions.success(task);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('Batch item failed:', error);
|
|
131
|
+
actions.fail(task);
|
|
132
|
+
|
|
133
|
+
// Optionally add retry tasks
|
|
134
|
+
if (task.retries < 3) {
|
|
135
|
+
actions.addTasks([{
|
|
136
|
+
...task,
|
|
137
|
+
retries: (task.retries || 0) + 1,
|
|
138
|
+
execute_at: new Date(Date.now() + 60000) // Retry in 1 minute
|
|
139
|
+
}]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Async Task Management
|
|
148
|
+
|
|
149
|
+
For long-running tasks that might exceed normal timeouts:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const heavyProcessingExecutor: ISingleTaskNonParallel<ProcessingData> = {
|
|
153
|
+
multiple: false,
|
|
154
|
+
parallel: false,
|
|
155
|
+
default_retries: 1,
|
|
156
|
+
store_on_failure: true,
|
|
157
|
+
|
|
158
|
+
// Configure async handoff for tasks taking longer than 30 seconds
|
|
159
|
+
asyncConfig: {
|
|
160
|
+
handoffTimeout: 30000, // 30 seconds
|
|
161
|
+
maxConcurrentAsync: 2 // Max 2 concurrent heavy tasks
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
async onTask(task, actions) {
|
|
165
|
+
try {
|
|
166
|
+
// This might take a very long time
|
|
167
|
+
const result = await performHeavyComputation(task.data);
|
|
168
|
+
actions.success(task);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
actions.fail(task);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Advanced Usage
|
|
177
|
+
|
|
178
|
+
### Task Queue Management
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import {TaskQueue} from '@supergrowthai/tq';
|
|
182
|
+
|
|
183
|
+
// Create a custom task queue instance
|
|
184
|
+
const customTaskQueue = new TaskQueue();
|
|
185
|
+
|
|
186
|
+
// Get information about registered queues
|
|
187
|
+
const queues = taskQueue.getQueues();
|
|
188
|
+
console.log('Registered queues:', queues);
|
|
189
|
+
|
|
190
|
+
// Get task types for a specific queue
|
|
191
|
+
const taskTypes = taskQueue.getTasksForQueue('email-queue');
|
|
192
|
+
console.log('Email queue task types:', taskTypes);
|
|
193
|
+
|
|
194
|
+
// Get a specific executor
|
|
195
|
+
const executor = taskQueue.getExecutor('email-queue', 'send-email');
|
|
196
|
+
if (executor) {
|
|
197
|
+
console.log('Found email executor');
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Error Handling and Retries
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const resilientExecutor: ISingleTaskNonParallel<ApiCallData> = {
|
|
205
|
+
multiple: false,
|
|
206
|
+
parallel: false,
|
|
207
|
+
default_retries: 5,
|
|
208
|
+
store_on_failure: true,
|
|
209
|
+
|
|
210
|
+
async onTask(task, actions) {
|
|
211
|
+
const maxRetries = task.retries || this.default_retries;
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const response = await callExternalAPI(task.data.endpoint, task.data.payload);
|
|
215
|
+
|
|
216
|
+
if (response.status === 200) {
|
|
217
|
+
actions.success(task);
|
|
218
|
+
} else {
|
|
219
|
+
throw new Error(`API returned status: ${response.status}`);
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.error(`API call failed (attempt ${task.retries || 0 + 1}/${maxRetries}):`, error);
|
|
223
|
+
|
|
224
|
+
if ((task.retries || 0) < maxRetries) {
|
|
225
|
+
// Create retry task with exponential backoff
|
|
226
|
+
const retryDelay = Math.pow(2, task.retries || 0) * 1000; // 1s, 2s, 4s, 8s, 16s
|
|
227
|
+
|
|
228
|
+
actions.addTasks([{
|
|
229
|
+
...task,
|
|
230
|
+
retries: (task.retries || 0) + 1,
|
|
231
|
+
execute_at: new Date(Date.now() + retryDelay)
|
|
232
|
+
}]);
|
|
233
|
+
} else {
|
|
234
|
+
actions.fail(task);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Working with Different Message Queue Providers
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import {QueueFactory} from '@supergrowthai/mq';
|
|
245
|
+
import {MemoryCacheAdapter} from '@supergrowthai/mq/adapters';
|
|
246
|
+
|
|
247
|
+
// Use with MongoDB queue
|
|
248
|
+
const mongoQueue = QueueFactory.create({
|
|
249
|
+
provider: 'mongodb',
|
|
250
|
+
cacheAdapter: new MemoryCacheAdapter()
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
taskQueue.register(mongoQueue, 'heavy-processing', 'compute', heavyProcessingExecutor);
|
|
254
|
+
|
|
255
|
+
// Use with Kinesis queue
|
|
256
|
+
const kinesisQueue = QueueFactory.create({
|
|
257
|
+
provider: 'kinesis',
|
|
258
|
+
kinesis: {instanceId: 'worker-1'}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
taskQueue.register(kinesisQueue, 'real-time', 'notification', notificationExecutor);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## TypeScript Support
|
|
265
|
+
|
|
266
|
+
The library provides full TypeScript support with generic task types:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import {TaskExecutor, ExecutorActions} from '@supergrowthai/tq/core/base/interfaces';
|
|
270
|
+
import {CronTask} from '@supergrowthai/database/types.server';
|
|
271
|
+
import {WithId} from 'mongodb';
|
|
272
|
+
|
|
273
|
+
// Define your task data type
|
|
274
|
+
interface EmailTaskData {
|
|
275
|
+
to: string;
|
|
276
|
+
subject: string;
|
|
277
|
+
body: string;
|
|
278
|
+
attachments?: string[];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Type-safe executor
|
|
282
|
+
const typedExecutor: ISingleTaskNonParallel<EmailTaskData> = {
|
|
283
|
+
multiple: false,
|
|
284
|
+
parallel: false,
|
|
285
|
+
default_retries: 3,
|
|
286
|
+
store_on_failure: true,
|
|
287
|
+
|
|
288
|
+
async onTask(
|
|
289
|
+
task: WithId<CronTask<EmailTaskData>>,
|
|
290
|
+
actions: ExecutorActions<EmailTaskData>
|
|
291
|
+
) {
|
|
292
|
+
// task.data is properly typed as EmailTaskData
|
|
293
|
+
console.log(`Sending email to: ${task.data.to}`);
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
await sendEmail(task.data);
|
|
297
|
+
actions.success(task);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
actions.fail(task);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Environment Integration
|
|
306
|
+
|
|
307
|
+
Task queue automatically handles environment-specific queue naming:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
// Queue names are automatically prefixed based on environment
|
|
311
|
+
// Development: 'dev-email-queue'
|
|
312
|
+
// Production: 'prod-email-queue'
|
|
313
|
+
// Test: 'test-email-queue'
|
|
314
|
+
|
|
315
|
+
taskQueue.register(messageQueue, 'email-queue', 'send', emailExecutor);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Best Practices
|
|
319
|
+
|
|
320
|
+
### 1. Task Idempotency
|
|
321
|
+
|
|
322
|
+
Ensure your tasks can be safely retried:
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
const idempotentExecutor: ISingleTaskNonParallel<UserUpdateData> = {
|
|
326
|
+
multiple: false,
|
|
327
|
+
parallel: false,
|
|
328
|
+
default_retries: 3,
|
|
329
|
+
store_on_failure: true,
|
|
330
|
+
|
|
331
|
+
async onTask(task, actions) {
|
|
332
|
+
try {
|
|
333
|
+
// Check if already processed
|
|
334
|
+
const user = await getUser(task.data.userId);
|
|
335
|
+
if (user.lastUpdated >= task.data.timestamp) {
|
|
336
|
+
console.log('Update already applied, skipping');
|
|
337
|
+
actions.success(task);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
await updateUser(task.data.userId, task.data.updates);
|
|
342
|
+
actions.success(task);
|
|
343
|
+
} catch (error) {
|
|
344
|
+
actions.fail(task);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### 2. Resource Management
|
|
351
|
+
|
|
352
|
+
Use parallel executors wisely to avoid overwhelming external services:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
const apiExecutor: ISingleTaskParallel<ApiTaskData> = {
|
|
356
|
+
multiple: false,
|
|
357
|
+
parallel: true,
|
|
358
|
+
chunkSize: 3, // Limit concurrent API calls
|
|
359
|
+
default_retries: 3,
|
|
360
|
+
store_on_failure: true,
|
|
361
|
+
|
|
362
|
+
async onTask(task, actions) {
|
|
363
|
+
// Rate limiting logic here
|
|
364
|
+
await rateLimiter.acquire();
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
const result = await callAPI(task.data);
|
|
368
|
+
actions.success(task);
|
|
369
|
+
} catch (error) {
|
|
370
|
+
actions.fail(task);
|
|
371
|
+
} finally {
|
|
372
|
+
rateLimiter.release();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### 3. Monitoring and Observability
|
|
379
|
+
|
|
380
|
+
Add logging and metrics to your executors:
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
const monitoredExecutor: ISingleTaskNonParallel<TaskData> = {
|
|
384
|
+
multiple: false,
|
|
385
|
+
parallel: false,
|
|
386
|
+
default_retries: 3,
|
|
387
|
+
store_on_failure: true,
|
|
388
|
+
|
|
389
|
+
async onTask(task, actions) {
|
|
390
|
+
const startTime = Date.now();
|
|
391
|
+
const taskId = task._id.toString();
|
|
392
|
+
|
|
393
|
+
console.log(`Starting task ${taskId} of type ${task.type}`);
|
|
394
|
+
|
|
395
|
+
try {
|
|
396
|
+
await processTask(task.data);
|
|
397
|
+
|
|
398
|
+
const duration = Date.now() - startTime;
|
|
399
|
+
console.log(`Task ${taskId} completed in ${duration}ms`);
|
|
400
|
+
|
|
401
|
+
// Send metrics to your monitoring system
|
|
402
|
+
metrics.histogram('task.duration', duration, {type: task.type, status: 'success'});
|
|
403
|
+
|
|
404
|
+
actions.success(task);
|
|
405
|
+
} catch (error) {
|
|
406
|
+
const duration = Date.now() - startTime;
|
|
407
|
+
console.error(`Task ${taskId} failed after ${duration}ms:`, error);
|
|
408
|
+
|
|
409
|
+
metrics.histogram('task.duration', duration, {type: task.type, status: 'failure'});
|
|
410
|
+
metrics.increment('task.failures', {type: task.type});
|
|
411
|
+
|
|
412
|
+
actions.fail(task);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## Integration with @supergrowthai/mq
|
|
419
|
+
|
|
420
|
+
This library requires @supergrowthai/mq for message queue functionality. See
|
|
421
|
+
the [@supergrowthai/mq documentation](../mq/README.md) for details on configuring different queue providers and cache
|
|
422
|
+
adapters.
|
|
423
|
+
|
|
424
|
+
## License
|
|
425
|
+
|
|
426
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|