@supergrowthai/tq 1.0.1-canary.03bf985
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 +538 -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 +2 -0
- package/dist/index.js +1734 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1734 -0
- package/dist/index.mjs.map +1 -0
- package/dist/src/adapters/IDatabaseAdapter.d.ts +61 -0
- package/dist/src/adapters/InMemoryAdapter.d.ts +24 -0
- package/dist/src/adapters/MongoDbAdapter.d.ts +34 -0
- package/dist/src/adapters/index.d.ts +4 -0
- package/dist/src/adapters/types.d.ts +9 -0
- package/dist/src/core/Actions.d.ts +33 -0
- package/dist/src/core/TaskHandler.d.ts +35 -0
- package/dist/src/core/TaskQueuesManager.d.ts +33 -0
- package/dist/src/core/TaskRunner.d.ts +26 -0
- package/dist/src/core/TaskStore.d.ts +63 -0
- package/dist/src/core/async/AsyncActions.d.ts +22 -0
- package/dist/src/core/async/AsyncTaskManager.d.ts +19 -0
- package/dist/src/core/async/async-task-manager.d.ts +25 -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-processor-types.d.ts +14 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/task-registry.d.ts +4 -0
- package/dist/src/test/task-queue.test.d.ts +6 -0
- package/dist/src/types.d.ts +1 -0
- package/dist/src/utils/task-id-gen.d.ts +4 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
# @supergrowthai/tq
|
|
2
|
+
|
|
3
|
+
A clean, dependency-injection based task queue management library with multiple executor types and async task handling.
|
|
4
|
+
Built on top of `@supergrowthai/mq` for flexible message queue backends.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Clean Architecture**: Constructor-based dependency injection with no global state
|
|
9
|
+
- **Multiple Executor Types**: Single task (parallel/non-parallel) and multi-task executors
|
|
10
|
+
- **Async Task Management**: Handle long-running tasks with configurable timeouts
|
|
11
|
+
- **Type-Safe**: Full TypeScript support with generic task types
|
|
12
|
+
- **Queue Integration**: Works with any message queue backend via `@supergrowthai/mq`
|
|
13
|
+
- **Named Exports**: Tree-shakable, explicit imports
|
|
14
|
+
- **Fail-Fast Design**: Required dependencies enforce proper configuration
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @supergrowthai/tq @supergrowthai/mq
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import {TaskQueue, TaskHandler} from '@supergrowthai/tq';
|
|
26
|
+
import {InMemoryQueue, ITasksAdapter} from '@supergrowthai/mq';
|
|
27
|
+
|
|
28
|
+
// 1. Set up your adapters (see @supergrowthai/mq docs for details)
|
|
29
|
+
const tasksAdapter: ITasksAdapter = {
|
|
30
|
+
// Your implementation
|
|
31
|
+
findScheduledTasks: () => Promise.resolve([]),
|
|
32
|
+
generateTaskId: () => `task-${Date.now()}`,
|
|
33
|
+
insertTasks: () => Promise.resolve(),
|
|
34
|
+
markTasksAsExecuted: () => Promise.resolve(),
|
|
35
|
+
markTasksAsFailed: () => Promise.resolve(),
|
|
36
|
+
markTasksAsProcessing: () => Promise.resolve()
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const databaseAdapter = /* your database adapter */;
|
|
40
|
+
const cacheAdapter = /* your cache adapter */;
|
|
41
|
+
|
|
42
|
+
// 2. Create instances with dependency injection
|
|
43
|
+
const messageQueue = new InMemoryQueue(tasksAdapter);
|
|
44
|
+
const taskQueue = new TaskQueue(messageQueue);
|
|
45
|
+
const taskHandler = new TaskHandler(
|
|
46
|
+
messageQueue,
|
|
47
|
+
taskQueue,
|
|
48
|
+
databaseAdapter,
|
|
49
|
+
cacheAdapter
|
|
50
|
+
// asyncTaskManager optional
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// 3. Register task executors
|
|
54
|
+
taskQueue.register('email-queue', 'send-email', {
|
|
55
|
+
multiple: false,
|
|
56
|
+
parallel: false,
|
|
57
|
+
default_retries: 3,
|
|
58
|
+
store_on_failure: true,
|
|
59
|
+
|
|
60
|
+
async onTask(task, actions) {
|
|
61
|
+
try {
|
|
62
|
+
await sendEmail(task.payload.to, task.payload.subject);
|
|
63
|
+
actions.success(task);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Failed to send email:', error);
|
|
66
|
+
actions.fail(task);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 4. Start processing
|
|
72
|
+
taskHandler.taskProcessServer();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Core Components
|
|
76
|
+
|
|
77
|
+
### TaskQueue
|
|
78
|
+
|
|
79
|
+
Manages task executor registration and retrieval:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import {TaskQueue} from '@supergrowthai/tq';
|
|
83
|
+
import {IMessageQueue} from '@supergrowthai/mq';
|
|
84
|
+
|
|
85
|
+
const taskQueue = new TaskQueue(messageQueue);
|
|
86
|
+
|
|
87
|
+
// Register executors
|
|
88
|
+
taskQueue.register('queue-name', 'task-type', executor);
|
|
89
|
+
|
|
90
|
+
// Get executor
|
|
91
|
+
const executor = taskQueue.getExecutor('queue-name', 'task-type');
|
|
92
|
+
|
|
93
|
+
// Get queue information
|
|
94
|
+
const queues = taskQueue.getQueues();
|
|
95
|
+
const taskTypes = taskQueue.getTasksForQueue('queue-name');
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### TaskHandler
|
|
99
|
+
|
|
100
|
+
Manages task processing, retries, and queue consumption:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import {TaskHandler} from '@supergrowthai/tq';
|
|
104
|
+
|
|
105
|
+
const taskHandler = new TaskHandler(
|
|
106
|
+
messageQueue, // IMessageQueue
|
|
107
|
+
taskQueue, // TaskQueue
|
|
108
|
+
databaseAdapter, // IDatabaseAdapter
|
|
109
|
+
cacheAdapter, // BaseCacheProvider<any>
|
|
110
|
+
asyncTaskManager // IAsyncTaskManager (optional)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// Start processing all registered queues
|
|
114
|
+
taskHandler.taskProcessServer();
|
|
115
|
+
|
|
116
|
+
// Or process specific queues
|
|
117
|
+
taskHandler.startConsumingTasks('email-queue');
|
|
118
|
+
|
|
119
|
+
// Process mature tasks (scheduled for future execution)
|
|
120
|
+
taskHandler.processMatureTasks();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### TaskRunner
|
|
124
|
+
|
|
125
|
+
Handles task execution with locking and async support:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import {TaskRunner} from '@supergrowthai/tq';
|
|
129
|
+
|
|
130
|
+
const taskRunner = new TaskRunner(
|
|
131
|
+
messageQueue,
|
|
132
|
+
taskQueue,
|
|
133
|
+
taskStore,
|
|
134
|
+
cacheProvider
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Run tasks
|
|
138
|
+
const result = await taskRunner.run(
|
|
139
|
+
'runner-id',
|
|
140
|
+
tasks,
|
|
141
|
+
asyncTaskManager // optional
|
|
142
|
+
);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Task Executor Types
|
|
146
|
+
|
|
147
|
+
### Single Task Non-Parallel Executor
|
|
148
|
+
|
|
149
|
+
For tasks that should be processed one at a time:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import {ISingleTaskNonParallel} from '@supergrowthai/tq';
|
|
153
|
+
|
|
154
|
+
interface EmailData {
|
|
155
|
+
to: string;
|
|
156
|
+
subject: string;
|
|
157
|
+
body: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const emailExecutor: ISingleTaskNonParallel<EmailData> = {
|
|
161
|
+
multiple: false,
|
|
162
|
+
parallel: false,
|
|
163
|
+
default_retries: 3,
|
|
164
|
+
store_on_failure: true,
|
|
165
|
+
|
|
166
|
+
async onTask(task, actions) {
|
|
167
|
+
try {
|
|
168
|
+
await sendEmail(task.payload);
|
|
169
|
+
actions.success(task);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error('Email sending failed:', error);
|
|
172
|
+
actions.fail(task);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
taskQueue.register('email-queue', 'send-email', emailExecutor);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Single Task Parallel Executor
|
|
181
|
+
|
|
182
|
+
For tasks that can be processed in parallel batches:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import {ISingleTaskParallel} from '@supergrowthai/tq';
|
|
186
|
+
|
|
187
|
+
const imageProcessorExecutor: ISingleTaskParallel<ImageData> = {
|
|
188
|
+
multiple: false,
|
|
189
|
+
parallel: true,
|
|
190
|
+
chunkSize: 5, // Process 5 images at a time
|
|
191
|
+
default_retries: 3,
|
|
192
|
+
store_on_failure: true,
|
|
193
|
+
|
|
194
|
+
async onTask(task, actions) {
|
|
195
|
+
try {
|
|
196
|
+
await processImage(task.payload.imageUrl, task.payload.filters);
|
|
197
|
+
actions.success(task);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
console.error('Image processing failed:', error);
|
|
200
|
+
actions.fail(task);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
taskQueue.register('image-queue', 'process-image', imageProcessorExecutor);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Multi-Task Executor
|
|
209
|
+
|
|
210
|
+
For processing multiple tasks together as a batch:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import {IMultiTaskExecutor} from '@supergrowthai/tq';
|
|
214
|
+
|
|
215
|
+
const batchProcessorExecutor: IMultiTaskExecutor<BatchData> = {
|
|
216
|
+
multiple: true,
|
|
217
|
+
default_retries: 2,
|
|
218
|
+
store_on_failure: true,
|
|
219
|
+
|
|
220
|
+
async onTasks(tasks, actions) {
|
|
221
|
+
console.log(`Processing batch of ${tasks.length} tasks`);
|
|
222
|
+
|
|
223
|
+
for (const task of tasks) {
|
|
224
|
+
try {
|
|
225
|
+
await processBatchItem(task.payload);
|
|
226
|
+
actions.success(task);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error('Batch item failed:', error);
|
|
229
|
+
actions.fail(task);
|
|
230
|
+
|
|
231
|
+
// Optionally add retry tasks
|
|
232
|
+
if ((task.retries || 0) < 3) {
|
|
233
|
+
actions.addTasks([{
|
|
234
|
+
...task,
|
|
235
|
+
retries: (task.retries || 0) + 1,
|
|
236
|
+
execute_at: new Date(Date.now() + 60000) // Retry in 1 minute
|
|
237
|
+
}]);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
taskQueue.register('batch-queue', 'process-batch', batchProcessorExecutor);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Async Task Management
|
|
248
|
+
|
|
249
|
+
For long-running tasks that might exceed normal timeouts:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import {AsyncTaskManager} from '@supergrowthai/tq';
|
|
253
|
+
|
|
254
|
+
// Set up async task manager
|
|
255
|
+
const asyncTaskManager = new AsyncTaskManager(maxConcurrent
|
|
256
|
+
:
|
|
257
|
+
5
|
|
258
|
+
)
|
|
259
|
+
;
|
|
260
|
+
|
|
261
|
+
const heavyProcessingExecutor: ISingleTaskNonParallel<ProcessingData> = {
|
|
262
|
+
multiple: false,
|
|
263
|
+
parallel: false,
|
|
264
|
+
default_retries: 1,
|
|
265
|
+
store_on_failure: true,
|
|
266
|
+
|
|
267
|
+
// Configure async handoff for tasks taking longer than 30 seconds
|
|
268
|
+
asyncConfig: {
|
|
269
|
+
handoffTimeout: 30000 // 30 seconds
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
async onTask(task, actions) {
|
|
273
|
+
try {
|
|
274
|
+
// This might take a very long time
|
|
275
|
+
const result = await performHeavyComputation(task.payload);
|
|
276
|
+
actions.success(task);
|
|
277
|
+
} catch (error) {
|
|
278
|
+
actions.fail(task);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// Pass async task manager to TaskHandler
|
|
284
|
+
const taskHandler = new TaskHandler(
|
|
285
|
+
messageQueue,
|
|
286
|
+
taskQueue,
|
|
287
|
+
databaseAdapter,
|
|
288
|
+
cacheAdapter,
|
|
289
|
+
asyncTaskManager // Now tasks can be handed off to async processing
|
|
290
|
+
);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Error Handling and Retries
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
const resilientExecutor: ISingleTaskNonParallel<ApiCallData> = {
|
|
297
|
+
multiple: false,
|
|
298
|
+
parallel: false,
|
|
299
|
+
default_retries: 5,
|
|
300
|
+
store_on_failure: true,
|
|
301
|
+
|
|
302
|
+
async onTask(task, actions) {
|
|
303
|
+
try {
|
|
304
|
+
const response = await callExternalAPI(task.payload.endpoint, task.payload.data);
|
|
305
|
+
|
|
306
|
+
if (response.status === 200) {
|
|
307
|
+
actions.success(task);
|
|
308
|
+
} else {
|
|
309
|
+
throw new Error(`API returned status: ${response.status}`);
|
|
310
|
+
}
|
|
311
|
+
} catch (error) {
|
|
312
|
+
const currentRetries = task.retries || 0;
|
|
313
|
+
console.error(`API call failed (attempt ${currentRetries + 1}/${this.default_retries}):`, error);
|
|
314
|
+
|
|
315
|
+
if (currentRetries < this.default_retries) {
|
|
316
|
+
// Create retry task with exponential backoff
|
|
317
|
+
const retryDelay = Math.pow(2, currentRetries) * 1000; // 1s, 2s, 4s, 8s, 16s
|
|
318
|
+
|
|
319
|
+
actions.addTasks([{
|
|
320
|
+
...task,
|
|
321
|
+
retries: currentRetries + 1,
|
|
322
|
+
execute_at: new Date(Date.now() + retryDelay)
|
|
323
|
+
}]);
|
|
324
|
+
} else {
|
|
325
|
+
actions.fail(task);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Working with Different Queue Providers
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import {MongoDBQueue, KinesisQueue, FileShardLockProvider} from '@supergrowthai/mq';
|
|
336
|
+
import {TaskQueue, TaskHandler} from '@supergrowthai/tq';
|
|
337
|
+
|
|
338
|
+
// MongoDB Queue Setup
|
|
339
|
+
const mongoQueue = new MongoDBQueue(cacheAdapter, tasksAdapter);
|
|
340
|
+
const mongoTaskQueue = new TaskQueue(mongoQueue);
|
|
341
|
+
const mongoTaskHandler = new TaskHandler(
|
|
342
|
+
mongoQueue,
|
|
343
|
+
mongoTaskQueue,
|
|
344
|
+
databaseAdapter,
|
|
345
|
+
cacheAdapter
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
// Kinesis Queue Setup
|
|
349
|
+
const shardLockProvider = new FileShardLockProvider();
|
|
350
|
+
const kinesisQueue = new KinesisQueue({
|
|
351
|
+
shardLockProvider,
|
|
352
|
+
instanceId: 'worker-1'
|
|
353
|
+
});
|
|
354
|
+
const kinesisTaskQueue = new TaskQueue(kinesisQueue);
|
|
355
|
+
const kinesisTaskHandler = new TaskHandler(
|
|
356
|
+
kinesisQueue,
|
|
357
|
+
kinesisTaskQueue,
|
|
358
|
+
databaseAdapter,
|
|
359
|
+
cacheAdapter
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
// Register different executors on different queues
|
|
363
|
+
mongoTaskQueue.register('heavy-processing', 'compute', heavyProcessingExecutor);
|
|
364
|
+
kinesisTaskQueue.register('real-time', 'notification', notificationExecutor);
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## Architecture Benefits
|
|
368
|
+
|
|
369
|
+
### No Global State
|
|
370
|
+
|
|
371
|
+
- All dependencies are injected via constructors
|
|
372
|
+
- No singletons or global variables
|
|
373
|
+
- Easy to test and mock
|
|
374
|
+
|
|
375
|
+
### Fail-Fast Design
|
|
376
|
+
|
|
377
|
+
- Required dependencies are enforced at compile time
|
|
378
|
+
- No optional parameters with defaults
|
|
379
|
+
- Clear error messages when dependencies are missing
|
|
380
|
+
|
|
381
|
+
### Clean Separation
|
|
382
|
+
|
|
383
|
+
- Queue management separate from task execution
|
|
384
|
+
- Pluggable storage and cache adapters
|
|
385
|
+
- Each component has a single responsibility
|
|
386
|
+
|
|
387
|
+
## TypeScript Support
|
|
388
|
+
|
|
389
|
+
Full TypeScript definitions with generic task types:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import {TaskExecutor, ExecutorActions, CronTask} from '@supergrowthai/tq';
|
|
393
|
+
|
|
394
|
+
// Define your task data type
|
|
395
|
+
interface EmailTaskData {
|
|
396
|
+
to: string;
|
|
397
|
+
subject: string;
|
|
398
|
+
body: string;
|
|
399
|
+
attachments?: string[];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Type-safe executor
|
|
403
|
+
const typedExecutor: ISingleTaskNonParallel<EmailTaskData> = {
|
|
404
|
+
multiple: false,
|
|
405
|
+
parallel: false,
|
|
406
|
+
default_retries: 3,
|
|
407
|
+
store_on_failure: true,
|
|
408
|
+
|
|
409
|
+
async onTask(
|
|
410
|
+
task: CronTask<EmailTaskData>,
|
|
411
|
+
actions: ExecutorActions<EmailTaskData>
|
|
412
|
+
) {
|
|
413
|
+
// task.payload is properly typed as EmailTaskData
|
|
414
|
+
console.log(`Sending email to: ${task.payload.to}`);
|
|
415
|
+
|
|
416
|
+
try {
|
|
417
|
+
await sendEmail(task.payload);
|
|
418
|
+
actions.success(task);
|
|
419
|
+
} catch (error) {
|
|
420
|
+
actions.fail(task);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Production Example
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
import {
|
|
430
|
+
TaskQueue,
|
|
431
|
+
TaskHandler,
|
|
432
|
+
TaskStore,
|
|
433
|
+
AsyncTaskManager
|
|
434
|
+
} from '@supergrowthai/tq';
|
|
435
|
+
import {MongoDBQueue, ITasksAdapter} from '@supergrowthai/mq';
|
|
436
|
+
import {RedisCacheProvider} from 'memoose-js';
|
|
437
|
+
|
|
438
|
+
// Production setup with all components
|
|
439
|
+
class ProductionTasksAdapter implements ITasksAdapter {
|
|
440
|
+
// Your database implementation
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const cacheProvider = new RedisCacheProvider('redis', {
|
|
444
|
+
host: process.env.REDIS_HOST,
|
|
445
|
+
port: parseInt(process.env.REDIS_PORT || '6379')
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
const messageQueue = new MongoDBQueue(cacheProvider, new ProductionTasksAdapter());
|
|
449
|
+
const taskQueue = new TaskQueue(messageQueue);
|
|
450
|
+
const asyncTaskManager = new AsyncTaskManager(10); // 10 concurrent async tasks
|
|
451
|
+
|
|
452
|
+
const taskHandler = new TaskHandler(
|
|
453
|
+
messageQueue,
|
|
454
|
+
taskQueue,
|
|
455
|
+
new MongoDbAdapter(), // Your database adapter
|
|
456
|
+
cacheProvider,
|
|
457
|
+
cacheProvider,
|
|
458
|
+
asyncTaskManager
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
// Register all your executors
|
|
462
|
+
taskQueue.register('email', 'send', emailExecutor);
|
|
463
|
+
taskQueue.register('notifications', 'push', pushNotificationExecutor);
|
|
464
|
+
taskQueue.register('reports', 'generate', reportGeneratorExecutor);
|
|
465
|
+
|
|
466
|
+
// Start processing
|
|
467
|
+
taskHandler.taskProcessServer();
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
## Best Practices
|
|
471
|
+
|
|
472
|
+
### 1. Task Idempotency
|
|
473
|
+
|
|
474
|
+
Ensure your tasks can be safely retried:
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
const idempotentExecutor: ISingleTaskNonParallel<UserUpdateData> = {
|
|
478
|
+
multiple: false,
|
|
479
|
+
parallel: false,
|
|
480
|
+
default_retries: 3,
|
|
481
|
+
store_on_failure: true,
|
|
482
|
+
|
|
483
|
+
async onTask(task, actions) {
|
|
484
|
+
try {
|
|
485
|
+
// Check if already processed
|
|
486
|
+
const user = await getUser(task.payload.userId);
|
|
487
|
+
if (user.lastUpdated >= task.payload.timestamp) {
|
|
488
|
+
console.log('Update already applied, skipping');
|
|
489
|
+
actions.success(task);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
await updateUser(task.payload.userId, task.payload.updates);
|
|
494
|
+
actions.success(task);
|
|
495
|
+
} catch (error) {
|
|
496
|
+
actions.fail(task);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### 2. Resource Management
|
|
503
|
+
|
|
504
|
+
Use parallel executors wisely to avoid overwhelming external services:
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
const apiExecutor: ISingleTaskParallel<ApiTaskData> = {
|
|
508
|
+
multiple: false,
|
|
509
|
+
parallel: true,
|
|
510
|
+
chunkSize: 3, // Limit concurrent API calls
|
|
511
|
+
default_retries: 3,
|
|
512
|
+
store_on_failure: true,
|
|
513
|
+
|
|
514
|
+
async onTask(task, actions) {
|
|
515
|
+
// Rate limiting logic here
|
|
516
|
+
await rateLimiter.acquire();
|
|
517
|
+
|
|
518
|
+
try {
|
|
519
|
+
const result = await callAPI(task.payload);
|
|
520
|
+
actions.success(task);
|
|
521
|
+
} catch (error) {
|
|
522
|
+
actions.fail(task);
|
|
523
|
+
} finally {
|
|
524
|
+
rateLimiter.release();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
## Integration with @supergrowthai/mq
|
|
531
|
+
|
|
532
|
+
This library requires `@supergrowthai/mq` for message queue functionality. See
|
|
533
|
+
the [@supergrowthai/mq documentation](../mq/README.md) for details on configuring different queue providers and
|
|
534
|
+
adapters.
|
|
535
|
+
|
|
536
|
+
## License
|
|
537
|
+
|
|
538
|
+
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":""}
|
package/dist/index.d.ts
ADDED