@supergrowthai/tq 1.0.9 → 1.0.10
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 +33 -0
- package/dist/{PrismaAdapter-xNqDYAC_.cjs → PrismaAdapter-CvM_XNtE.cjs} +49 -21
- package/dist/PrismaAdapter-CvM_XNtE.cjs.map +1 -0
- package/dist/{PrismaAdapter-BD8f3tk9.js → PrismaAdapter-Dy7MV090.js} +49 -21
- package/dist/PrismaAdapter-Dy7MV090.js.map +1 -0
- package/dist/adapters/index.cjs +1 -1
- package/dist/adapters/index.mjs +1 -1
- package/dist/index.cjs +39 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +39 -4
- package/dist/index.mjs.map +1 -1
- package/dist/src/adapters/PrismaAdapter.d.cts +24 -1
- package/dist/src/adapters/PrismaAdapter.d.ts +24 -1
- package/package.json +7 -7
- package/dist/PrismaAdapter-BD8f3tk9.js.map +0 -1
- package/dist/PrismaAdapter-xNqDYAC_.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -693,6 +693,39 @@ const mongoAdapter = new MongoDbAdapter(mongoCollection);
|
|
|
693
693
|
const memoryAdapter = new InMemoryAdapter();
|
|
694
694
|
```
|
|
695
695
|
|
|
696
|
+
### PrismaAdapter Performance Optimization
|
|
697
|
+
|
|
698
|
+
The default `PrismaAdapter.addTasksToScheduled()` uses sequential creates for maximum database compatibility
|
|
699
|
+
(SQLite, CockroachDB, etc.). For high-throughput Postgres/MySQL deployments, override with batch operations:
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
import {PrismaAdapter} from '@supergrowthai/tq';
|
|
703
|
+
|
|
704
|
+
class OptimizedPrismaAdapter extends PrismaAdapter {
|
|
705
|
+
async addTasksToScheduled(tasks) {
|
|
706
|
+
if (!tasks.length) return [];
|
|
707
|
+
|
|
708
|
+
// Batch insert with duplicate handling (Postgres/MySQL only)
|
|
709
|
+
await this.delegate.createMany({
|
|
710
|
+
data: tasks.map(task => ({
|
|
711
|
+
...task,
|
|
712
|
+
id: task.id || this.generateId(),
|
|
713
|
+
status: task.status || 'scheduled',
|
|
714
|
+
retries: task.retries || 0,
|
|
715
|
+
created_at: task.created_at || new Date(),
|
|
716
|
+
updated_at: new Date(),
|
|
717
|
+
processing_started_at: task.processing_started_at || new Date()
|
|
718
|
+
})),
|
|
719
|
+
skipDuplicates: true
|
|
720
|
+
});
|
|
721
|
+
return tasks;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
**Note:** `createMany` with `skipDuplicates` is not supported on all databases (e.g., SQLite).
|
|
727
|
+
The default implementation ensures compatibility at the cost of O(n) database round-trips.
|
|
728
|
+
|
|
696
729
|
### Custom Storage Adapter
|
|
697
730
|
|
|
698
731
|
Implement the `ITaskStorageAdapter` interface for custom storage backends:
|
|
@@ -171,7 +171,7 @@ class MongoDbAdapter {
|
|
|
171
171
|
}
|
|
172
172
|
}));
|
|
173
173
|
if (bulkOps.length > 0) {
|
|
174
|
-
await collection.bulkWrite(bulkOps);
|
|
174
|
+
await collection.bulkWrite(bulkOps, { ordered: false });
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
async upsertTasks(tasks) {
|
|
@@ -180,7 +180,7 @@ class MongoDbAdapter {
|
|
|
180
180
|
const now = /* @__PURE__ */ new Date();
|
|
181
181
|
const bulkOps = tasks.map((task) => {
|
|
182
182
|
const id = task.id || this.generateId();
|
|
183
|
-
const { id: _id, ...rest } = task;
|
|
183
|
+
const { id: _id, status, execute_at, execution_stats, updated_at, ...rest } = task;
|
|
184
184
|
return {
|
|
185
185
|
updateOne: {
|
|
186
186
|
filter: { _id: id },
|
|
@@ -201,7 +201,7 @@ class MongoDbAdapter {
|
|
|
201
201
|
}
|
|
202
202
|
};
|
|
203
203
|
});
|
|
204
|
-
await collection.bulkWrite(bulkOps);
|
|
204
|
+
await collection.bulkWrite(bulkOps, { ordered: false });
|
|
205
205
|
}
|
|
206
206
|
generateId() {
|
|
207
207
|
return new mongodb.ObjectId();
|
|
@@ -393,26 +393,54 @@ class PrismaAdapter {
|
|
|
393
393
|
get delegate() {
|
|
394
394
|
return this.config.prismaClient[this.config.messageModel];
|
|
395
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* Persist tasks to the database as scheduled.
|
|
398
|
+
*
|
|
399
|
+
* **Default implementation:** Uses individual creates with duplicate detection
|
|
400
|
+
* for maximum database compatibility (SQLite, Postgres, MySQL, etc.).
|
|
401
|
+
*
|
|
402
|
+
* **Performance note:** This is O(n) database round-trips. For high-throughput
|
|
403
|
+
* scenarios (100+ tasks/batch), override this method with a batch implementation:
|
|
404
|
+
*
|
|
405
|
+
* @example PostgreSQL/MySQL optimization:
|
|
406
|
+
* ```typescript
|
|
407
|
+
* class OptimizedPrismaAdapter extends PrismaAdapter {
|
|
408
|
+
* async addTasksToScheduled(tasks) {
|
|
409
|
+
* if (!tasks.length) return [];
|
|
410
|
+
* await this.delegate.createMany({
|
|
411
|
+
* data: tasks.map(t => ({ ...t, id: t.id || this.generateId() })),
|
|
412
|
+
* skipDuplicates: true
|
|
413
|
+
* });
|
|
414
|
+
* return tasks;
|
|
415
|
+
* }
|
|
416
|
+
* }
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
396
419
|
async addTasksToScheduled(tasks) {
|
|
397
420
|
if (!tasks.length) return [];
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
421
|
+
if (tasks.length > 50) {
|
|
422
|
+
logger.warn(`[PrismaAdapter] Processing ${tasks.length} tasks sequentially (O(n) round-trips). For Postgres/MySQL, override addTasksToScheduled with createMany for better performance.`);
|
|
423
|
+
}
|
|
424
|
+
const results = [];
|
|
425
|
+
for (const task of tasks) {
|
|
426
|
+
try {
|
|
427
|
+
await this.delegate.create({
|
|
428
|
+
data: {
|
|
429
|
+
...task,
|
|
430
|
+
id: task.id || this.generateId(),
|
|
431
|
+
status: task.status || "scheduled",
|
|
432
|
+
retries: task.retries || 0,
|
|
433
|
+
created_at: task.created_at || /* @__PURE__ */ new Date(),
|
|
434
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
435
|
+
processing_started_at: task.processing_started_at || /* @__PURE__ */ new Date()
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
results.push(task);
|
|
439
|
+
} catch (error) {
|
|
440
|
+
logger.warn(`Task skipped (likely duplicate): ${error}`);
|
|
441
|
+
}
|
|
415
442
|
}
|
|
443
|
+
return results;
|
|
416
444
|
}
|
|
417
445
|
async getMatureTasks(timestamp) {
|
|
418
446
|
const staleTimestamp = Date.now() - TWO_DAYS_MS;
|
|
@@ -556,4 +584,4 @@ class PrismaAdapter {
|
|
|
556
584
|
exports.InMemoryAdapter = InMemoryAdapter;
|
|
557
585
|
exports.MongoDbAdapter = MongoDbAdapter;
|
|
558
586
|
exports.PrismaAdapter = PrismaAdapter;
|
|
559
|
-
//# sourceMappingURL=PrismaAdapter-
|
|
587
|
+
//# sourceMappingURL=PrismaAdapter-CvM_XNtE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrismaAdapter-CvM_XNtE.cjs","sources":["../src/adapters/MongoDbAdapter.ts","../src/adapters/InMemoryAdapter.ts","../src/adapters/PrismaAdapter.ts"],"sourcesContent":["import {Collection, ObjectId} from \"mongodb\";\nimport {ITaskStorageAdapter, TaskStorageLifecycleConfig} from \"./ITaskStorageAdapter.js\";\nimport {CronTask} from \"./types.js\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport type {ITaskLifecycleProvider} from \"../core/lifecycle.js\";\n\nconst logger = new Logger('MongoDbAdapter', LogLevel.INFO);\n\nconst TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1000;\n\n/**\n * Convert MongoDB document with _id to CronTask with id\n */\nfunction toPublicTask<T>({_id, ...rest}: Omit<CronTask<T>, 'id'> & { _id: T }): CronTask<T> {\n return {...rest, id: _id} as CronTask<T>;\n}\n\n/**\n * MongoDB task storage adapter for @supergrowthai/tq.\n *\n * @description Persists scheduled tasks to MongoDB collection with status tracking.\n * Uses application-level locking designed for single-instance deployments.\n *\n * @use-case Single-instance production deployments\n * @multi-instance NOT SAFE - designed for single-instance use.\n * For multi-instance deployments, implement a distributed locking strategy\n * or use a Kinesis-based solution with Redis lock provider.\n * @persistence Full - tasks stored in MongoDB until processed/expired\n * @requires MongoDB connection via abstract `collection` getter\n *\n * @features\n * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset\n * - Bulk operations for efficiency\n * - Task expiration cleanup\n *\n * @example\n * ```typescript\n * class MyTaskStorage extends MongoDbAdapter {\n * get collection() { return db.collection('scheduled_tasks'); }\n * }\n * const adapter = new MyTaskStorage();\n * ```\n */\nexport abstract class MongoDbAdapter implements ITaskStorageAdapter<ObjectId> {\n private lifecycleProvider?: ITaskLifecycleProvider;\n private lifecycleMode: 'sync' | 'async' = 'async';\n\n protected constructor() {\n }\n\n setLifecycleConfig(config: TaskStorageLifecycleConfig): void {\n this.lifecycleProvider = config.lifecycleProvider;\n this.lifecycleMode = config.mode || 'async';\n }\n\n private emitLifecycleEvent<T>(\n callback: ((ctx: T) => void | Promise<void>) | undefined,\n ctx: T\n ): void {\n if (!callback) return;\n try {\n const result = callback(ctx);\n if (result instanceof Promise) {\n result.catch(err => logger.error(`[TQ] Lifecycle callback error: ${err}`));\n }\n } catch (err) {\n logger.error(`[TQ] Lifecycle callback error: ${err}`);\n }\n }\n\n abstract get collection(): Promise<Collection<Omit<CronTask<ObjectId>, 'id'> & { _id?: ObjectId; }>> ;\n\n async addTasksToScheduled(tasks: CronTask<ObjectId>[]): Promise<CronTask<ObjectId>[]> {\n if (!tasks.length) return [];\n\n const collection = await this.collection;\n\n const transformedTasks = tasks.map((task) => ({\n _id: task.id,\n type: task.type,\n payload: task.payload,\n execute_at: task.execute_at,\n status: task.status || 'scheduled',\n retries: task.retries || 0,\n created_at: task.created_at || new Date(),\n updated_at: new Date(),\n queue_id: task.queue_id,\n processing_started_at: task.processing_started_at || new Date(),\n expires_at: task.expires_at,\n task_group: task.task_group,\n task_hash: task.task_hash,\n retry_after: task.retry_after,\n execution_stats: task.execution_stats,\n force_store: task.force_store\n }));\n\n try {\n await collection.insertMany(transformedTasks, {ordered: false});\n return transformedTasks.map(toPublicTask);\n } catch (error: unknown) {\n if (error && typeof error === 'object' && 'writeErrors' in error) {\n const mongoError = error as { writeErrors: Array<{ index: number }> };\n const successfulTasks = transformedTasks.filter((_, index) =>\n !mongoError.writeErrors.some((e) => e.index === index)\n );\n return successfulTasks.map(toPublicTask);\n }\n throw error;\n }\n }\n\n async getMatureTasks(timestamp: number): Promise<CronTask<ObjectId>[]> {\n const collection = await this.collection;\n\n // Phase 1: Reset stale processing tasks\n const staleTimestamp = Date.now() - TWO_DAYS_MS;\n await collection.updateMany(\n {\n status: 'processing',\n processing_started_at: {$lt: new Date(staleTimestamp)}\n },\n {\n $set: {status: 'scheduled'}\n }\n );\n\n // Phase 2: Fetch and mark mature tasks\n const filter = {\n status: 'scheduled' as const,\n execute_at: {$lte: new Date(timestamp)}\n };\n\n const tasks = await collection\n .find(filter)\n .limit(1000)\n .toArray();\n\n if (tasks.length > 0) {\n const taskIds = tasks.map(t => t._id);\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'processing',\n processing_started_at: new Date()\n }\n }\n );\n }\n\n return tasks.map(toPublicTask);\n }\n\n async markTasksAsProcessing(tasks: CronTask<ObjectId>[], processingStartedAt: Date): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'processing',\n processing_started_at: processingStartedAt,\n updated_at: new Date()\n }\n }\n );\n }\n\n async markTasksAsExecuted(tasks: CronTask<ObjectId>[]): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'executed',\n updated_at: new Date()\n }\n }\n );\n }\n\n async markTasksAsFailed(tasks: CronTask<ObjectId>[]): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'failed',\n updated_at: new Date()\n }\n }\n );\n }\n\n async getTasksByIds(taskIds: ObjectId[]): Promise<CronTask<ObjectId>[]> {\n const collection = await this.collection;\n\n return collection\n .find({_id: {$in: taskIds}})\n .toArray()\n .then(result => result.map(toPublicTask));\n }\n\n async getCleanupStats(): Promise<{ orphanedTasks: number; expiredTasks: number }> {\n const collection = await this.collection;\n\n const orphanedBefore = new Date(Date.now() - TWO_DAYS_MS);\n const orphanedTasks = await collection.countDocuments({\n status: 'processing',\n processing_started_at: {$lt: orphanedBefore}\n });\n\n const expiredTasks = await collection.countDocuments({\n expires_at: {$lt: new Date()}\n });\n\n return {orphanedTasks, expiredTasks};\n }\n\n async cleanupTasks(orphanedBefore: Date, expiredBefore: Date): Promise<void> {\n const collection = await this.collection;\n\n // Clean up orphaned tasks\n await collection.deleteMany({\n status: 'processing',\n processing_started_at: {$lt: orphanedBefore}\n });\n\n // Clean up expired tasks\n await collection.deleteMany({\n expires_at: {$lt: expiredBefore}\n });\n }\n\n async updateTasks(updates: Array<{ id: ObjectId; updates: Partial<CronTask<ObjectId>> }>): Promise<void> {\n const collection = await this.collection;\n\n const bulkOps = updates.map(({id, updates}) => ({\n updateOne: {\n filter: {_id: id},\n update: {\n $set: {\n ...updates,\n updated_at: new Date()\n }\n }\n }\n }));\n\n if (bulkOps.length > 0) {\n // ordered: false allows remaining ops to continue if one fails (e.g., duplicate key)\n await collection.bulkWrite(bulkOps, {ordered: false});\n }\n }\n\n async upsertTasks(tasks: CronTask<ObjectId>[]): Promise<void> {\n if (!tasks.length) return;\n const collection = await this.collection;\n const now = new Date();\n\n const bulkOps = tasks.map(task => {\n const id = task.id || this.generateId();\n const {id: _id, status, execute_at, execution_stats, updated_at, ...rest} = task;\n return {\n updateOne: {\n filter: {_id: id},\n update: {\n $set: {\n status: task.status,\n execute_at: task.execute_at,\n execution_stats: task.execution_stats,\n updated_at: now\n },\n $setOnInsert: {\n ...rest,\n created_at: task.created_at || now,\n processing_started_at: task.processing_started_at || now\n }\n },\n upsert: true\n }\n };\n });\n\n // ordered: false allows remaining ops to continue if one fails\n await collection.bulkWrite(bulkOps, {ordered: false});\n }\n\n generateId() {\n return new ObjectId();\n }\n\n async close() {\n }\n\n async initialize() {\n }\n\n async markTasksAsIgnored(tasks: CronTask<ObjectId>[]): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'ignored',\n //update execution_stats\n updated_at: new Date()\n },\n }\n );\n }\n}","import {ITaskStorageAdapter, TaskStorageLifecycleConfig} from \"./ITaskStorageAdapter\";\nimport {CronTask} from \"./types\";\nimport type {ITaskLifecycleProvider} from \"../core/lifecycle.js\";\n\n/**\n * In-memory task storage adapter for @supergrowthai/tq.\n *\n * @description Stores scheduled tasks in memory using a Map.\n * Data is lost on process restart - use for development and testing only.\n *\n * @use-case Development, testing, and prototyping\n * @multi-instance NOT SAFE - data is not shared between processes\n * @persistence NONE - all tasks lost on restart\n *\n * @features\n * - Fast in-memory operations\n * - Simple cleanup implementation\n * - Auto-generated string IDs\n *\n * @example\n * ```typescript\n * const adapter = new InMemoryAdapter();\n * const taskHandler = new TaskHandler(queue, taskQueue, adapter, cache);\n * ```\n */\nclass InMemoryAdapter implements ITaskStorageAdapter<string> {\n private scheduledTasks: Map<string, CronTask<string>> = new Map();\n private lifecycleProvider?: ITaskLifecycleProvider;\n private lifecycleMode: 'sync' | 'async' = 'async';\n\n setLifecycleConfig(config: TaskStorageLifecycleConfig): void {\n this.lifecycleProvider = config.lifecycleProvider;\n this.lifecycleMode = config.mode || 'async';\n }\n\n private emitLifecycleEvent<T>(\n callback: ((ctx: T) => void | Promise<void>) | undefined,\n ctx: T\n ): void {\n if (!callback) return;\n try {\n const result = callback(ctx);\n if (result instanceof Promise) {\n result.catch(err => console.error(`[TQ] Lifecycle callback error: ${err}`));\n }\n } catch (err) {\n console.error(`[TQ] Lifecycle callback error: ${err}`);\n }\n }\n\n async addTasksToScheduled(tasks: CronTask<string>[]): Promise<CronTask<string>[]> {\n const addedTasks = tasks.map(task => {\n const id = task.id || this.generateId();\n const taskWithId = {...task, id};\n this.scheduledTasks.set(id, taskWithId);\n return taskWithId;\n });\n return addedTasks;\n }\n\n async getMatureTasks(timestamp: number): Promise<CronTask<string>[]> {\n const matureTasks: CronTask<string>[] = [];\n for (const [id, task] of Array.from(this.scheduledTasks.entries())) {\n if (task.execute_at.getTime() <= timestamp && task.status !== 'processing' && task.status !== 'executed') {\n matureTasks.push(task);\n }\n }\n return matureTasks;\n }\n\n async markTasksAsProcessing(tasks: CronTask<string>[], processingStartedAt: Date): Promise<void> {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'processing';\n existingTask.processing_started_at = processingStartedAt;\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n\n async markTasksAsExecuted(tasks: CronTask<string>[]): Promise<void> {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'executed';\n existingTask.execute_at = new Date();\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n\n async markTasksAsFailed(tasks: CronTask<string>[]): Promise<void> {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'failed';\n existingTask.execution_stats = {...existingTask.execution_stats, failed_at: new Date()};\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n\n async getTasksByIds(taskIds: string[]): Promise<CronTask<string>[]> {\n return taskIds.map(id => this.scheduledTasks.get(id)).filter(Boolean) as CronTask<string>[];\n }\n\n async updateTasks(updates: Array<{ id: string; updates: Partial<CronTask<string>> }>): Promise<void> {\n for (const {id, updates: taskUpdates} of updates) {\n const task = this.scheduledTasks.get(id);\n if (task) {\n Object.assign(task, taskUpdates);\n this.scheduledTasks.set(id, task);\n }\n }\n }\n\n async upsertTasks(tasks: CronTask<string>[]): Promise<void> {\n for (const task of tasks) {\n const id = task.id || this.generateId();\n const existing = this.scheduledTasks.get(id);\n if (existing) {\n Object.assign(existing, {\n status: task.status,\n execute_at: task.execute_at,\n execution_stats: task.execution_stats,\n updated_at: new Date()\n });\n } else {\n this.scheduledTasks.set(id, {...task, id});\n }\n }\n }\n\n async getCleanupStats(): Promise<{ orphanedTasks: number; expiredTasks: number }> {\n let orphanedTasks = 0;\n let expiredTasks = 0;\n const now = Date.now();\n\n for (const task of Array.from(this.scheduledTasks.values())) {\n if (task.status === 'processing' && task.processing_started_at && (now - task.processing_started_at.getTime()) > 300000) {\n orphanedTasks++;\n }\n if (task.expires_at && now > task.expires_at.getTime()) {\n expiredTasks++;\n }\n }\n\n return {orphanedTasks, expiredTasks};\n }\n\n async cleanupTasks(orphanedBefore: Date, expiredBefore: Date): Promise<void> {\n for (const [id, task] of Array.from(this.scheduledTasks.entries())) {\n const shouldDelete =\n (task.status === 'processing' && task.processing_started_at && task.processing_started_at < orphanedBefore) ||\n (task.expires_at && task.expires_at < expiredBefore);\n\n if (shouldDelete) {\n this.scheduledTasks.delete(id);\n }\n }\n }\n\n async initialize(): Promise<void> {\n // No initialization needed for memory adapter\n }\n\n async close(): Promise<void> {\n this.scheduledTasks.clear();\n }\n\n generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n async markTasksAsIgnored(tasks: CronTask<string>[]) {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'ignored';\n existingTask.execution_stats = {...existingTask.execution_stats, ignore_reason: \"unknown type\"};\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n}\n\nexport {InMemoryAdapter}","import {ITaskStorageAdapter, TaskStorageLifecycleConfig} from \"./ITaskStorageAdapter.js\";\nimport {CronTask} from \"./types.js\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {PrismaClient} from \"@prisma/client/extension\";\nimport type {ITaskLifecycleProvider} from \"../core/lifecycle.js\";\n\nconst logger = new Logger('PrismaAdapter', LogLevel.INFO);\nconst TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1000;\n\n\n// ---- Type utilities ----\n\n/** A Prisma client that is guaranteed to have model delegate K. */\nexport type ClientWithModel<K extends keyof PrismaClient> =\n Pick<PrismaClient, K>;\n\n/** Extract the entity (row) type from a model delegate. */\ntype EntityOf<D> =\n D extends { findUnique(args: any): Promise<infer U | null> } ? U :\n D extends { findFirst(args: any): Promise<infer U | null> } ? U :\n D extends { findMany(args?: any): Promise<(infer U)[]> } ? U :\n never;\n\n/** Compile-time guard: model's entity must be compatible with the shape you require. */\ntype EnsureModelShape<Delegate, Needed> =\n EntityOf<Delegate> extends Needed ? unknown : never;\n\n/**\n * Prisma task storage adapter for @supergrowthai/tq.\n *\n * @description Persists scheduled tasks to any Prisma model with status tracking.\n * Uses application-level locking designed for single-instance deployments.\n *\n * @use-case Single-instance production deployments with Prisma ORM\n * @multi-instance NOT SAFE - designed for single-instance use.\n * For multi-instance deployments, implement a distributed locking strategy\n * or use a Kinesis-based solution with Redis lock provider.\n * @persistence Full - tasks stored in database until processed/expired\n * @requires Prisma client with a model matching CronTask structure\n *\n * @features\n * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset\n * - Transaction support for batch updates\n * - Task expiration cleanup\n *\n * @typeParam TId - The ID type (string, number, etc.)\n * @typeParam K - The Prisma model key (e.g. 'scheduledTask')\n * @typeParam Msg - The task type extending CronTask<TId>\n *\n * @example\n * ```typescript\n * const adapter = new PrismaAdapter({\n * prismaClient: prisma,\n * messageModel: 'scheduledTask'\n * });\n * ```\n */\nexport class PrismaAdapter<\n TId = any,\n K extends keyof PrismaClient = never,\n Msg extends CronTask<TId> = CronTask<TId>\n> implements ITaskStorageAdapter<TId> {\n private lifecycleProvider?: ITaskLifecycleProvider;\n private lifecycleMode: 'sync' | 'async' = 'async';\n\n constructor(\n private config: {\n prismaClient: ClientWithModel<K>;\n messageModel: K;\n /**\n * Phantom type param that enforces:\n * - client has model K\n * - entity type of client[K] extends Msg (which extends BaseMessage<TId>)\n * Do not pass at runtime.\n */\n _shapeCheck?: EnsureModelShape<PrismaClient[K], Msg> & (Msg extends CronTask<TId> & {\n id: TId\n } ? unknown : never);\n }\n ) {\n }\n\n setLifecycleConfig(config: TaskStorageLifecycleConfig): void {\n this.lifecycleProvider = config.lifecycleProvider;\n this.lifecycleMode = config.mode || 'async';\n }\n\n private emitLifecycleEvent<T>(\n callback: ((ctx: T) => void | Promise<void>) | undefined,\n ctx: T\n ): void {\n if (!callback) return;\n try {\n const result = callback(ctx);\n if (result instanceof Promise) {\n result.catch(err => logger.error(`[TQ] Lifecycle callback error: ${err}`));\n }\n } catch (err) {\n logger.error(`[TQ] Lifecycle callback error: ${err}`);\n }\n }\n\n get prismaClient(): PrismaClient {\n return this.config.prismaClient;\n }\n\n get taskTableName(): string {\n return String(this.config.messageModel);\n }\n\n protected get delegate(): PrismaClient[K] {\n return this.config.prismaClient[this.config.messageModel];\n }\n\n /**\n * Persist tasks to the database as scheduled.\n *\n * **Default implementation:** Uses individual creates with duplicate detection\n * for maximum database compatibility (SQLite, Postgres, MySQL, etc.).\n *\n * **Performance note:** This is O(n) database round-trips. For high-throughput\n * scenarios (100+ tasks/batch), override this method with a batch implementation:\n *\n * @example PostgreSQL/MySQL optimization:\n * ```typescript\n * class OptimizedPrismaAdapter extends PrismaAdapter {\n * async addTasksToScheduled(tasks) {\n * if (!tasks.length) return [];\n * await this.delegate.createMany({\n * data: tasks.map(t => ({ ...t, id: t.id || this.generateId() })),\n * skipDuplicates: true\n * });\n * return tasks;\n * }\n * }\n * ```\n */\n async addTasksToScheduled(tasks: CronTask<TId>[]): Promise<CronTask<TId>[]> {\n if (!tasks.length) return [];\n\n // Performance hint for high-throughput scenarios\n if (tasks.length > 50) {\n logger.warn(`[PrismaAdapter] Processing ${tasks.length} tasks sequentially (O(n) round-trips). For Postgres/MySQL, override addTasksToScheduled with createMany for better performance.`);\n }\n\n // Sequential creates for broad DB compatibility (SQLite, CockroachDB, etc.)\n // Override this method for batch optimization on Postgres/MySQL\n const results: CronTask<TId>[] = [];\n for (const task of tasks) {\n try {\n await this.delegate.create({\n data: {\n ...task,\n id: task.id || this.generateId(),\n status: task.status || 'scheduled',\n retries: task.retries || 0,\n created_at: task.created_at || new Date(),\n updated_at: new Date(),\n processing_started_at: task.processing_started_at || new Date()\n }\n });\n results.push(task);\n } catch (error: unknown) {\n logger.warn(`Task skipped (likely duplicate): ${error}`);\n }\n }\n return results;\n }\n\n async getMatureTasks(timestamp: number): Promise<CronTask<TId>[]> {\n const staleTimestamp = Date.now() - TWO_DAYS_MS;\n\n await this.delegate.updateMany({\n where: {\n status: 'processing',\n processing_started_at: {lt: new Date(staleTimestamp)}\n },\n data: {status: 'scheduled'}\n });\n\n const tasks = await this.delegate.findMany({\n where: {\n status: 'scheduled',\n execute_at: {lte: new Date(timestamp)}\n },\n take: 1000,\n orderBy: {execute_at: 'asc'}\n });\n\n if (tasks.length > 0) {\n const taskIds = tasks.map((t: any) => t.id);\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {\n status: 'processing',\n processing_started_at: new Date()\n }\n });\n }\n\n return tasks;\n }\n\n async markTasksAsProcessing(tasks: CronTask<TId>[], processingStartedAt: Date): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {\n status: 'processing',\n processing_started_at: processingStartedAt,\n updated_at: new Date()\n }\n });\n }\n\n async markTasksAsExecuted(tasks: CronTask<TId>[]): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {status: 'executed', updated_at: new Date()}\n });\n }\n\n async markTasksAsFailed(tasks: CronTask<TId>[]): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {status: 'failed', updated_at: new Date()}\n });\n }\n\n async markTasksAsIgnored(tasks: CronTask<TId>[]): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {status: 'ignored', updated_at: new Date()}\n });\n }\n\n async getTasksByIds(taskIds: TId[]): Promise<CronTask<TId>[]> {\n if (!taskIds.length) return [];\n\n return this.delegate.findMany({\n where: {id: {in: taskIds}}\n });\n }\n\n async updateTasks(updatesList: Array<{ id: TId; updates: Partial<CronTask<TId>> }>): Promise<void> {\n //fixme do we need a transaction. good but defo ?\n await this.prismaClient\n .$transaction(async (prisma) => {\n for (const {id, updates} of updatesList) {\n await (prisma as any)[this.taskTableName]\n .update({\n where: {id: id},\n data: {...updates, updated_at: new Date()}\n });\n }\n });\n }\n\n async upsertTasks(tasks: CronTask<TId>[]): Promise<void> {\n if (!tasks.length) return;\n\n const now = new Date();\n const delegate = this.delegate;\n\n // Each task may have different status/execute_at/execution_stats,\n // so per-task upsert is unavoidable. Wrapped in a transaction for atomicity.\n await this.prismaClient\n .$transaction(\n tasks.map(task => delegate.upsert({\n where: {id: task.id},\n create: {\n ...task,\n created_at: task.created_at || now,\n updated_at: now,\n processing_started_at: task.processing_started_at || now\n },\n update: {\n status: task.status,\n execute_at: task.execute_at,\n execution_stats: task.execution_stats,\n updated_at: now\n }\n }))\n );\n }\n\n async getCleanupStats(): Promise<{ orphanedTasks: number; expiredTasks: number }> {\n const orphanedBefore = new Date(Date.now() - TWO_DAYS_MS);\n\n const [orphanedTasks, expiredTasks] = await Promise.all([\n this.delegate.count({\n where: {\n status: 'processing',\n processing_started_at: {lt: orphanedBefore}\n }\n }),\n this.delegate.count({\n where: {expires_at: {lt: new Date()}}\n })\n ]);\n\n return {orphanedTasks, expiredTasks};\n }\n\n async cleanupTasks(orphanedBefore: Date, expiredBefore: Date): Promise<void> {\n await Promise.all([\n this.delegate.deleteMany({\n where: {\n status: 'processing',\n processing_started_at: {lt: orphanedBefore}\n }\n }),\n this.delegate.deleteMany({\n where: {expires_at: {lt: expiredBefore}}\n })\n ]);\n }\n\n generateId(): TId {\n //needs to be overriden when prisma client is of mongodb\n return crypto.randomUUID() as TId;\n }\n\n async initialize(): Promise<void> {\n }\n\n async close(): Promise<void> {\n }\n}"],"names":["logger","Logger","LogLevel","TWO_DAYS_MS","updates","ObjectId"],"mappings":"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"}
|
|
@@ -170,7 +170,7 @@ class MongoDbAdapter {
|
|
|
170
170
|
}
|
|
171
171
|
}));
|
|
172
172
|
if (bulkOps.length > 0) {
|
|
173
|
-
await collection.bulkWrite(bulkOps);
|
|
173
|
+
await collection.bulkWrite(bulkOps, { ordered: false });
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
async upsertTasks(tasks) {
|
|
@@ -179,7 +179,7 @@ class MongoDbAdapter {
|
|
|
179
179
|
const now = /* @__PURE__ */ new Date();
|
|
180
180
|
const bulkOps = tasks.map((task) => {
|
|
181
181
|
const id = task.id || this.generateId();
|
|
182
|
-
const { id: _id, ...rest } = task;
|
|
182
|
+
const { id: _id, status, execute_at, execution_stats, updated_at, ...rest } = task;
|
|
183
183
|
return {
|
|
184
184
|
updateOne: {
|
|
185
185
|
filter: { _id: id },
|
|
@@ -200,7 +200,7 @@ class MongoDbAdapter {
|
|
|
200
200
|
}
|
|
201
201
|
};
|
|
202
202
|
});
|
|
203
|
-
await collection.bulkWrite(bulkOps);
|
|
203
|
+
await collection.bulkWrite(bulkOps, { ordered: false });
|
|
204
204
|
}
|
|
205
205
|
generateId() {
|
|
206
206
|
return new ObjectId();
|
|
@@ -392,26 +392,54 @@ class PrismaAdapter {
|
|
|
392
392
|
get delegate() {
|
|
393
393
|
return this.config.prismaClient[this.config.messageModel];
|
|
394
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Persist tasks to the database as scheduled.
|
|
397
|
+
*
|
|
398
|
+
* **Default implementation:** Uses individual creates with duplicate detection
|
|
399
|
+
* for maximum database compatibility (SQLite, Postgres, MySQL, etc.).
|
|
400
|
+
*
|
|
401
|
+
* **Performance note:** This is O(n) database round-trips. For high-throughput
|
|
402
|
+
* scenarios (100+ tasks/batch), override this method with a batch implementation:
|
|
403
|
+
*
|
|
404
|
+
* @example PostgreSQL/MySQL optimization:
|
|
405
|
+
* ```typescript
|
|
406
|
+
* class OptimizedPrismaAdapter extends PrismaAdapter {
|
|
407
|
+
* async addTasksToScheduled(tasks) {
|
|
408
|
+
* if (!tasks.length) return [];
|
|
409
|
+
* await this.delegate.createMany({
|
|
410
|
+
* data: tasks.map(t => ({ ...t, id: t.id || this.generateId() })),
|
|
411
|
+
* skipDuplicates: true
|
|
412
|
+
* });
|
|
413
|
+
* return tasks;
|
|
414
|
+
* }
|
|
415
|
+
* }
|
|
416
|
+
* ```
|
|
417
|
+
*/
|
|
395
418
|
async addTasksToScheduled(tasks) {
|
|
396
419
|
if (!tasks.length) return [];
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
420
|
+
if (tasks.length > 50) {
|
|
421
|
+
logger.warn(`[PrismaAdapter] Processing ${tasks.length} tasks sequentially (O(n) round-trips). For Postgres/MySQL, override addTasksToScheduled with createMany for better performance.`);
|
|
422
|
+
}
|
|
423
|
+
const results = [];
|
|
424
|
+
for (const task of tasks) {
|
|
425
|
+
try {
|
|
426
|
+
await this.delegate.create({
|
|
427
|
+
data: {
|
|
428
|
+
...task,
|
|
429
|
+
id: task.id || this.generateId(),
|
|
430
|
+
status: task.status || "scheduled",
|
|
431
|
+
retries: task.retries || 0,
|
|
432
|
+
created_at: task.created_at || /* @__PURE__ */ new Date(),
|
|
433
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
434
|
+
processing_started_at: task.processing_started_at || /* @__PURE__ */ new Date()
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
results.push(task);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
logger.warn(`Task skipped (likely duplicate): ${error}`);
|
|
440
|
+
}
|
|
414
441
|
}
|
|
442
|
+
return results;
|
|
415
443
|
}
|
|
416
444
|
async getMatureTasks(timestamp) {
|
|
417
445
|
const staleTimestamp = Date.now() - TWO_DAYS_MS;
|
|
@@ -557,4 +585,4 @@ export {
|
|
|
557
585
|
MongoDbAdapter as M,
|
|
558
586
|
PrismaAdapter as P
|
|
559
587
|
};
|
|
560
|
-
//# sourceMappingURL=PrismaAdapter-
|
|
588
|
+
//# sourceMappingURL=PrismaAdapter-Dy7MV090.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PrismaAdapter-Dy7MV090.js","sources":["../src/adapters/MongoDbAdapter.ts","../src/adapters/InMemoryAdapter.ts","../src/adapters/PrismaAdapter.ts"],"sourcesContent":["import {Collection, ObjectId} from \"mongodb\";\nimport {ITaskStorageAdapter, TaskStorageLifecycleConfig} from \"./ITaskStorageAdapter.js\";\nimport {CronTask} from \"./types.js\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport type {ITaskLifecycleProvider} from \"../core/lifecycle.js\";\n\nconst logger = new Logger('MongoDbAdapter', LogLevel.INFO);\n\nconst TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1000;\n\n/**\n * Convert MongoDB document with _id to CronTask with id\n */\nfunction toPublicTask<T>({_id, ...rest}: Omit<CronTask<T>, 'id'> & { _id: T }): CronTask<T> {\n return {...rest, id: _id} as CronTask<T>;\n}\n\n/**\n * MongoDB task storage adapter for @supergrowthai/tq.\n *\n * @description Persists scheduled tasks to MongoDB collection with status tracking.\n * Uses application-level locking designed for single-instance deployments.\n *\n * @use-case Single-instance production deployments\n * @multi-instance NOT SAFE - designed for single-instance use.\n * For multi-instance deployments, implement a distributed locking strategy\n * or use a Kinesis-based solution with Redis lock provider.\n * @persistence Full - tasks stored in MongoDB until processed/expired\n * @requires MongoDB connection via abstract `collection` getter\n *\n * @features\n * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset\n * - Bulk operations for efficiency\n * - Task expiration cleanup\n *\n * @example\n * ```typescript\n * class MyTaskStorage extends MongoDbAdapter {\n * get collection() { return db.collection('scheduled_tasks'); }\n * }\n * const adapter = new MyTaskStorage();\n * ```\n */\nexport abstract class MongoDbAdapter implements ITaskStorageAdapter<ObjectId> {\n private lifecycleProvider?: ITaskLifecycleProvider;\n private lifecycleMode: 'sync' | 'async' = 'async';\n\n protected constructor() {\n }\n\n setLifecycleConfig(config: TaskStorageLifecycleConfig): void {\n this.lifecycleProvider = config.lifecycleProvider;\n this.lifecycleMode = config.mode || 'async';\n }\n\n private emitLifecycleEvent<T>(\n callback: ((ctx: T) => void | Promise<void>) | undefined,\n ctx: T\n ): void {\n if (!callback) return;\n try {\n const result = callback(ctx);\n if (result instanceof Promise) {\n result.catch(err => logger.error(`[TQ] Lifecycle callback error: ${err}`));\n }\n } catch (err) {\n logger.error(`[TQ] Lifecycle callback error: ${err}`);\n }\n }\n\n abstract get collection(): Promise<Collection<Omit<CronTask<ObjectId>, 'id'> & { _id?: ObjectId; }>> ;\n\n async addTasksToScheduled(tasks: CronTask<ObjectId>[]): Promise<CronTask<ObjectId>[]> {\n if (!tasks.length) return [];\n\n const collection = await this.collection;\n\n const transformedTasks = tasks.map((task) => ({\n _id: task.id,\n type: task.type,\n payload: task.payload,\n execute_at: task.execute_at,\n status: task.status || 'scheduled',\n retries: task.retries || 0,\n created_at: task.created_at || new Date(),\n updated_at: new Date(),\n queue_id: task.queue_id,\n processing_started_at: task.processing_started_at || new Date(),\n expires_at: task.expires_at,\n task_group: task.task_group,\n task_hash: task.task_hash,\n retry_after: task.retry_after,\n execution_stats: task.execution_stats,\n force_store: task.force_store\n }));\n\n try {\n await collection.insertMany(transformedTasks, {ordered: false});\n return transformedTasks.map(toPublicTask);\n } catch (error: unknown) {\n if (error && typeof error === 'object' && 'writeErrors' in error) {\n const mongoError = error as { writeErrors: Array<{ index: number }> };\n const successfulTasks = transformedTasks.filter((_, index) =>\n !mongoError.writeErrors.some((e) => e.index === index)\n );\n return successfulTasks.map(toPublicTask);\n }\n throw error;\n }\n }\n\n async getMatureTasks(timestamp: number): Promise<CronTask<ObjectId>[]> {\n const collection = await this.collection;\n\n // Phase 1: Reset stale processing tasks\n const staleTimestamp = Date.now() - TWO_DAYS_MS;\n await collection.updateMany(\n {\n status: 'processing',\n processing_started_at: {$lt: new Date(staleTimestamp)}\n },\n {\n $set: {status: 'scheduled'}\n }\n );\n\n // Phase 2: Fetch and mark mature tasks\n const filter = {\n status: 'scheduled' as const,\n execute_at: {$lte: new Date(timestamp)}\n };\n\n const tasks = await collection\n .find(filter)\n .limit(1000)\n .toArray();\n\n if (tasks.length > 0) {\n const taskIds = tasks.map(t => t._id);\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'processing',\n processing_started_at: new Date()\n }\n }\n );\n }\n\n return tasks.map(toPublicTask);\n }\n\n async markTasksAsProcessing(tasks: CronTask<ObjectId>[], processingStartedAt: Date): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'processing',\n processing_started_at: processingStartedAt,\n updated_at: new Date()\n }\n }\n );\n }\n\n async markTasksAsExecuted(tasks: CronTask<ObjectId>[]): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'executed',\n updated_at: new Date()\n }\n }\n );\n }\n\n async markTasksAsFailed(tasks: CronTask<ObjectId>[]): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'failed',\n updated_at: new Date()\n }\n }\n );\n }\n\n async getTasksByIds(taskIds: ObjectId[]): Promise<CronTask<ObjectId>[]> {\n const collection = await this.collection;\n\n return collection\n .find({_id: {$in: taskIds}})\n .toArray()\n .then(result => result.map(toPublicTask));\n }\n\n async getCleanupStats(): Promise<{ orphanedTasks: number; expiredTasks: number }> {\n const collection = await this.collection;\n\n const orphanedBefore = new Date(Date.now() - TWO_DAYS_MS);\n const orphanedTasks = await collection.countDocuments({\n status: 'processing',\n processing_started_at: {$lt: orphanedBefore}\n });\n\n const expiredTasks = await collection.countDocuments({\n expires_at: {$lt: new Date()}\n });\n\n return {orphanedTasks, expiredTasks};\n }\n\n async cleanupTasks(orphanedBefore: Date, expiredBefore: Date): Promise<void> {\n const collection = await this.collection;\n\n // Clean up orphaned tasks\n await collection.deleteMany({\n status: 'processing',\n processing_started_at: {$lt: orphanedBefore}\n });\n\n // Clean up expired tasks\n await collection.deleteMany({\n expires_at: {$lt: expiredBefore}\n });\n }\n\n async updateTasks(updates: Array<{ id: ObjectId; updates: Partial<CronTask<ObjectId>> }>): Promise<void> {\n const collection = await this.collection;\n\n const bulkOps = updates.map(({id, updates}) => ({\n updateOne: {\n filter: {_id: id},\n update: {\n $set: {\n ...updates,\n updated_at: new Date()\n }\n }\n }\n }));\n\n if (bulkOps.length > 0) {\n // ordered: false allows remaining ops to continue if one fails (e.g., duplicate key)\n await collection.bulkWrite(bulkOps, {ordered: false});\n }\n }\n\n async upsertTasks(tasks: CronTask<ObjectId>[]): Promise<void> {\n if (!tasks.length) return;\n const collection = await this.collection;\n const now = new Date();\n\n const bulkOps = tasks.map(task => {\n const id = task.id || this.generateId();\n const {id: _id, status, execute_at, execution_stats, updated_at, ...rest} = task;\n return {\n updateOne: {\n filter: {_id: id},\n update: {\n $set: {\n status: task.status,\n execute_at: task.execute_at,\n execution_stats: task.execution_stats,\n updated_at: now\n },\n $setOnInsert: {\n ...rest,\n created_at: task.created_at || now,\n processing_started_at: task.processing_started_at || now\n }\n },\n upsert: true\n }\n };\n });\n\n // ordered: false allows remaining ops to continue if one fails\n await collection.bulkWrite(bulkOps, {ordered: false});\n }\n\n generateId() {\n return new ObjectId();\n }\n\n async close() {\n }\n\n async initialize() {\n }\n\n async markTasksAsIgnored(tasks: CronTask<ObjectId>[]): Promise<void> {\n const collection = await this.collection;\n const taskIds = tasks.map(t => t.id).filter(Boolean) as ObjectId[];\n\n\n await collection.updateMany(\n {_id: {$in: taskIds}},\n {\n $set: {\n status: 'ignored',\n //update execution_stats\n updated_at: new Date()\n },\n }\n );\n }\n}","import {ITaskStorageAdapter, TaskStorageLifecycleConfig} from \"./ITaskStorageAdapter\";\nimport {CronTask} from \"./types\";\nimport type {ITaskLifecycleProvider} from \"../core/lifecycle.js\";\n\n/**\n * In-memory task storage adapter for @supergrowthai/tq.\n *\n * @description Stores scheduled tasks in memory using a Map.\n * Data is lost on process restart - use for development and testing only.\n *\n * @use-case Development, testing, and prototyping\n * @multi-instance NOT SAFE - data is not shared between processes\n * @persistence NONE - all tasks lost on restart\n *\n * @features\n * - Fast in-memory operations\n * - Simple cleanup implementation\n * - Auto-generated string IDs\n *\n * @example\n * ```typescript\n * const adapter = new InMemoryAdapter();\n * const taskHandler = new TaskHandler(queue, taskQueue, adapter, cache);\n * ```\n */\nclass InMemoryAdapter implements ITaskStorageAdapter<string> {\n private scheduledTasks: Map<string, CronTask<string>> = new Map();\n private lifecycleProvider?: ITaskLifecycleProvider;\n private lifecycleMode: 'sync' | 'async' = 'async';\n\n setLifecycleConfig(config: TaskStorageLifecycleConfig): void {\n this.lifecycleProvider = config.lifecycleProvider;\n this.lifecycleMode = config.mode || 'async';\n }\n\n private emitLifecycleEvent<T>(\n callback: ((ctx: T) => void | Promise<void>) | undefined,\n ctx: T\n ): void {\n if (!callback) return;\n try {\n const result = callback(ctx);\n if (result instanceof Promise) {\n result.catch(err => console.error(`[TQ] Lifecycle callback error: ${err}`));\n }\n } catch (err) {\n console.error(`[TQ] Lifecycle callback error: ${err}`);\n }\n }\n\n async addTasksToScheduled(tasks: CronTask<string>[]): Promise<CronTask<string>[]> {\n const addedTasks = tasks.map(task => {\n const id = task.id || this.generateId();\n const taskWithId = {...task, id};\n this.scheduledTasks.set(id, taskWithId);\n return taskWithId;\n });\n return addedTasks;\n }\n\n async getMatureTasks(timestamp: number): Promise<CronTask<string>[]> {\n const matureTasks: CronTask<string>[] = [];\n for (const [id, task] of Array.from(this.scheduledTasks.entries())) {\n if (task.execute_at.getTime() <= timestamp && task.status !== 'processing' && task.status !== 'executed') {\n matureTasks.push(task);\n }\n }\n return matureTasks;\n }\n\n async markTasksAsProcessing(tasks: CronTask<string>[], processingStartedAt: Date): Promise<void> {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'processing';\n existingTask.processing_started_at = processingStartedAt;\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n\n async markTasksAsExecuted(tasks: CronTask<string>[]): Promise<void> {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'executed';\n existingTask.execute_at = new Date();\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n\n async markTasksAsFailed(tasks: CronTask<string>[]): Promise<void> {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'failed';\n existingTask.execution_stats = {...existingTask.execution_stats, failed_at: new Date()};\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n\n async getTasksByIds(taskIds: string[]): Promise<CronTask<string>[]> {\n return taskIds.map(id => this.scheduledTasks.get(id)).filter(Boolean) as CronTask<string>[];\n }\n\n async updateTasks(updates: Array<{ id: string; updates: Partial<CronTask<string>> }>): Promise<void> {\n for (const {id, updates: taskUpdates} of updates) {\n const task = this.scheduledTasks.get(id);\n if (task) {\n Object.assign(task, taskUpdates);\n this.scheduledTasks.set(id, task);\n }\n }\n }\n\n async upsertTasks(tasks: CronTask<string>[]): Promise<void> {\n for (const task of tasks) {\n const id = task.id || this.generateId();\n const existing = this.scheduledTasks.get(id);\n if (existing) {\n Object.assign(existing, {\n status: task.status,\n execute_at: task.execute_at,\n execution_stats: task.execution_stats,\n updated_at: new Date()\n });\n } else {\n this.scheduledTasks.set(id, {...task, id});\n }\n }\n }\n\n async getCleanupStats(): Promise<{ orphanedTasks: number; expiredTasks: number }> {\n let orphanedTasks = 0;\n let expiredTasks = 0;\n const now = Date.now();\n\n for (const task of Array.from(this.scheduledTasks.values())) {\n if (task.status === 'processing' && task.processing_started_at && (now - task.processing_started_at.getTime()) > 300000) {\n orphanedTasks++;\n }\n if (task.expires_at && now > task.expires_at.getTime()) {\n expiredTasks++;\n }\n }\n\n return {orphanedTasks, expiredTasks};\n }\n\n async cleanupTasks(orphanedBefore: Date, expiredBefore: Date): Promise<void> {\n for (const [id, task] of Array.from(this.scheduledTasks.entries())) {\n const shouldDelete =\n (task.status === 'processing' && task.processing_started_at && task.processing_started_at < orphanedBefore) ||\n (task.expires_at && task.expires_at < expiredBefore);\n\n if (shouldDelete) {\n this.scheduledTasks.delete(id);\n }\n }\n }\n\n async initialize(): Promise<void> {\n // No initialization needed for memory adapter\n }\n\n async close(): Promise<void> {\n this.scheduledTasks.clear();\n }\n\n generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n async markTasksAsIgnored(tasks: CronTask<string>[]) {\n for (const task of tasks) {\n const existingTask = this.scheduledTasks.get(task.id!);\n if (existingTask) {\n existingTask.status = 'ignored';\n existingTask.execution_stats = {...existingTask.execution_stats, ignore_reason: \"unknown type\"};\n this.scheduledTasks.set(task.id!, existingTask);\n }\n }\n }\n}\n\nexport {InMemoryAdapter}","import {ITaskStorageAdapter, TaskStorageLifecycleConfig} from \"./ITaskStorageAdapter.js\";\nimport {CronTask} from \"./types.js\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {PrismaClient} from \"@prisma/client/extension\";\nimport type {ITaskLifecycleProvider} from \"../core/lifecycle.js\";\n\nconst logger = new Logger('PrismaAdapter', LogLevel.INFO);\nconst TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1000;\n\n\n// ---- Type utilities ----\n\n/** A Prisma client that is guaranteed to have model delegate K. */\nexport type ClientWithModel<K extends keyof PrismaClient> =\n Pick<PrismaClient, K>;\n\n/** Extract the entity (row) type from a model delegate. */\ntype EntityOf<D> =\n D extends { findUnique(args: any): Promise<infer U | null> } ? U :\n D extends { findFirst(args: any): Promise<infer U | null> } ? U :\n D extends { findMany(args?: any): Promise<(infer U)[]> } ? U :\n never;\n\n/** Compile-time guard: model's entity must be compatible with the shape you require. */\ntype EnsureModelShape<Delegate, Needed> =\n EntityOf<Delegate> extends Needed ? unknown : never;\n\n/**\n * Prisma task storage adapter for @supergrowthai/tq.\n *\n * @description Persists scheduled tasks to any Prisma model with status tracking.\n * Uses application-level locking designed for single-instance deployments.\n *\n * @use-case Single-instance production deployments with Prisma ORM\n * @multi-instance NOT SAFE - designed for single-instance use.\n * For multi-instance deployments, implement a distributed locking strategy\n * or use a Kinesis-based solution with Redis lock provider.\n * @persistence Full - tasks stored in database until processed/expired\n * @requires Prisma client with a model matching CronTask structure\n *\n * @features\n * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset\n * - Transaction support for batch updates\n * - Task expiration cleanup\n *\n * @typeParam TId - The ID type (string, number, etc.)\n * @typeParam K - The Prisma model key (e.g. 'scheduledTask')\n * @typeParam Msg - The task type extending CronTask<TId>\n *\n * @example\n * ```typescript\n * const adapter = new PrismaAdapter({\n * prismaClient: prisma,\n * messageModel: 'scheduledTask'\n * });\n * ```\n */\nexport class PrismaAdapter<\n TId = any,\n K extends keyof PrismaClient = never,\n Msg extends CronTask<TId> = CronTask<TId>\n> implements ITaskStorageAdapter<TId> {\n private lifecycleProvider?: ITaskLifecycleProvider;\n private lifecycleMode: 'sync' | 'async' = 'async';\n\n constructor(\n private config: {\n prismaClient: ClientWithModel<K>;\n messageModel: K;\n /**\n * Phantom type param that enforces:\n * - client has model K\n * - entity type of client[K] extends Msg (which extends BaseMessage<TId>)\n * Do not pass at runtime.\n */\n _shapeCheck?: EnsureModelShape<PrismaClient[K], Msg> & (Msg extends CronTask<TId> & {\n id: TId\n } ? unknown : never);\n }\n ) {\n }\n\n setLifecycleConfig(config: TaskStorageLifecycleConfig): void {\n this.lifecycleProvider = config.lifecycleProvider;\n this.lifecycleMode = config.mode || 'async';\n }\n\n private emitLifecycleEvent<T>(\n callback: ((ctx: T) => void | Promise<void>) | undefined,\n ctx: T\n ): void {\n if (!callback) return;\n try {\n const result = callback(ctx);\n if (result instanceof Promise) {\n result.catch(err => logger.error(`[TQ] Lifecycle callback error: ${err}`));\n }\n } catch (err) {\n logger.error(`[TQ] Lifecycle callback error: ${err}`);\n }\n }\n\n get prismaClient(): PrismaClient {\n return this.config.prismaClient;\n }\n\n get taskTableName(): string {\n return String(this.config.messageModel);\n }\n\n protected get delegate(): PrismaClient[K] {\n return this.config.prismaClient[this.config.messageModel];\n }\n\n /**\n * Persist tasks to the database as scheduled.\n *\n * **Default implementation:** Uses individual creates with duplicate detection\n * for maximum database compatibility (SQLite, Postgres, MySQL, etc.).\n *\n * **Performance note:** This is O(n) database round-trips. For high-throughput\n * scenarios (100+ tasks/batch), override this method with a batch implementation:\n *\n * @example PostgreSQL/MySQL optimization:\n * ```typescript\n * class OptimizedPrismaAdapter extends PrismaAdapter {\n * async addTasksToScheduled(tasks) {\n * if (!tasks.length) return [];\n * await this.delegate.createMany({\n * data: tasks.map(t => ({ ...t, id: t.id || this.generateId() })),\n * skipDuplicates: true\n * });\n * return tasks;\n * }\n * }\n * ```\n */\n async addTasksToScheduled(tasks: CronTask<TId>[]): Promise<CronTask<TId>[]> {\n if (!tasks.length) return [];\n\n // Performance hint for high-throughput scenarios\n if (tasks.length > 50) {\n logger.warn(`[PrismaAdapter] Processing ${tasks.length} tasks sequentially (O(n) round-trips). For Postgres/MySQL, override addTasksToScheduled with createMany for better performance.`);\n }\n\n // Sequential creates for broad DB compatibility (SQLite, CockroachDB, etc.)\n // Override this method for batch optimization on Postgres/MySQL\n const results: CronTask<TId>[] = [];\n for (const task of tasks) {\n try {\n await this.delegate.create({\n data: {\n ...task,\n id: task.id || this.generateId(),\n status: task.status || 'scheduled',\n retries: task.retries || 0,\n created_at: task.created_at || new Date(),\n updated_at: new Date(),\n processing_started_at: task.processing_started_at || new Date()\n }\n });\n results.push(task);\n } catch (error: unknown) {\n logger.warn(`Task skipped (likely duplicate): ${error}`);\n }\n }\n return results;\n }\n\n async getMatureTasks(timestamp: number): Promise<CronTask<TId>[]> {\n const staleTimestamp = Date.now() - TWO_DAYS_MS;\n\n await this.delegate.updateMany({\n where: {\n status: 'processing',\n processing_started_at: {lt: new Date(staleTimestamp)}\n },\n data: {status: 'scheduled'}\n });\n\n const tasks = await this.delegate.findMany({\n where: {\n status: 'scheduled',\n execute_at: {lte: new Date(timestamp)}\n },\n take: 1000,\n orderBy: {execute_at: 'asc'}\n });\n\n if (tasks.length > 0) {\n const taskIds = tasks.map((t: any) => t.id);\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {\n status: 'processing',\n processing_started_at: new Date()\n }\n });\n }\n\n return tasks;\n }\n\n async markTasksAsProcessing(tasks: CronTask<TId>[], processingStartedAt: Date): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {\n status: 'processing',\n processing_started_at: processingStartedAt,\n updated_at: new Date()\n }\n });\n }\n\n async markTasksAsExecuted(tasks: CronTask<TId>[]): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {status: 'executed', updated_at: new Date()}\n });\n }\n\n async markTasksAsFailed(tasks: CronTask<TId>[]): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {status: 'failed', updated_at: new Date()}\n });\n }\n\n async markTasksAsIgnored(tasks: CronTask<TId>[]): Promise<void> {\n const taskIds = tasks.map(t => t.id).filter(Boolean);\n if (!taskIds.length) return;\n\n await this.delegate.updateMany({\n where: {id: {in: taskIds}},\n data: {status: 'ignored', updated_at: new Date()}\n });\n }\n\n async getTasksByIds(taskIds: TId[]): Promise<CronTask<TId>[]> {\n if (!taskIds.length) return [];\n\n return this.delegate.findMany({\n where: {id: {in: taskIds}}\n });\n }\n\n async updateTasks(updatesList: Array<{ id: TId; updates: Partial<CronTask<TId>> }>): Promise<void> {\n //fixme do we need a transaction. good but defo ?\n await this.prismaClient\n .$transaction(async (prisma) => {\n for (const {id, updates} of updatesList) {\n await (prisma as any)[this.taskTableName]\n .update({\n where: {id: id},\n data: {...updates, updated_at: new Date()}\n });\n }\n });\n }\n\n async upsertTasks(tasks: CronTask<TId>[]): Promise<void> {\n if (!tasks.length) return;\n\n const now = new Date();\n const delegate = this.delegate;\n\n // Each task may have different status/execute_at/execution_stats,\n // so per-task upsert is unavoidable. Wrapped in a transaction for atomicity.\n await this.prismaClient\n .$transaction(\n tasks.map(task => delegate.upsert({\n where: {id: task.id},\n create: {\n ...task,\n created_at: task.created_at || now,\n updated_at: now,\n processing_started_at: task.processing_started_at || now\n },\n update: {\n status: task.status,\n execute_at: task.execute_at,\n execution_stats: task.execution_stats,\n updated_at: now\n }\n }))\n );\n }\n\n async getCleanupStats(): Promise<{ orphanedTasks: number; expiredTasks: number }> {\n const orphanedBefore = new Date(Date.now() - TWO_DAYS_MS);\n\n const [orphanedTasks, expiredTasks] = await Promise.all([\n this.delegate.count({\n where: {\n status: 'processing',\n processing_started_at: {lt: orphanedBefore}\n }\n }),\n this.delegate.count({\n where: {expires_at: {lt: new Date()}}\n })\n ]);\n\n return {orphanedTasks, expiredTasks};\n }\n\n async cleanupTasks(orphanedBefore: Date, expiredBefore: Date): Promise<void> {\n await Promise.all([\n this.delegate.deleteMany({\n where: {\n status: 'processing',\n processing_started_at: {lt: orphanedBefore}\n }\n }),\n this.delegate.deleteMany({\n where: {expires_at: {lt: expiredBefore}}\n })\n ]);\n }\n\n generateId(): TId {\n //needs to be overriden when prisma client is of mongodb\n return crypto.randomUUID() as TId;\n }\n\n async initialize(): Promise<void> {\n }\n\n async close(): Promise<void> {\n }\n}"],"names":["logger","TWO_DAYS_MS","updates"],"mappings":"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"}
|
package/dist/adapters/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const PrismaAdapter = require("../PrismaAdapter-
|
|
3
|
+
const PrismaAdapter = require("../PrismaAdapter-CvM_XNtE.cjs");
|
|
4
4
|
exports.InMemoryAdapter = PrismaAdapter.InMemoryAdapter;
|
|
5
5
|
exports.MongoDbAdapter = PrismaAdapter.MongoDbAdapter;
|
|
6
6
|
exports.PrismaAdapter = PrismaAdapter.PrismaAdapter;
|
package/dist/adapters/index.mjs
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -45,7 +45,7 @@ var __callDispose = (stack, error, hasError) => {
|
|
|
45
45
|
return next();
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
48
|
-
const PrismaAdapter = require("./PrismaAdapter-
|
|
48
|
+
const PrismaAdapter = require("./PrismaAdapter-CvM_XNtE.cjs");
|
|
49
49
|
const mq = require("@supergrowthai/mq");
|
|
50
50
|
const client = require("./client-DgdG7pT6.cjs");
|
|
51
51
|
const utils_taskIdGen = require("./utils/task-id-gen.cjs");
|
|
@@ -152,7 +152,7 @@ class TaskStore {
|
|
|
152
152
|
payload: task.payload,
|
|
153
153
|
execute_at: task.execute_at,
|
|
154
154
|
expires_at: task.expires_at,
|
|
155
|
-
status: "scheduled",
|
|
155
|
+
status: task.status || "scheduled",
|
|
156
156
|
task_group: task.task_group,
|
|
157
157
|
task_hash: task.task_hash,
|
|
158
158
|
retries: task.retries || 0,
|
|
@@ -1002,9 +1002,12 @@ class TaskHandler {
|
|
|
1002
1002
|
const executeTime = task.execute_at;
|
|
1003
1003
|
const timeDifference = (executeTime.getTime() - currentTime.getTime()) / 1e3 / 60;
|
|
1004
1004
|
const queue = task.queue_id;
|
|
1005
|
-
if (timeDifference > 2
|
|
1005
|
+
if (timeDifference > 2) {
|
|
1006
1006
|
acc.future[queue] = acc.future[queue] || [];
|
|
1007
1007
|
acc.future[queue].push(task);
|
|
1008
|
+
} else if (force_store) {
|
|
1009
|
+
acc.forceStoreImmediate[queue] = acc.forceStoreImmediate[queue] || [];
|
|
1010
|
+
acc.forceStoreImmediate[queue].push(task);
|
|
1008
1011
|
} else {
|
|
1009
1012
|
acc.immediate[queue] = acc.immediate[queue] || [];
|
|
1010
1013
|
acc.immediate[queue].push(task);
|
|
@@ -1013,7 +1016,8 @@ class TaskHandler {
|
|
|
1013
1016
|
},
|
|
1014
1017
|
{
|
|
1015
1018
|
future: {},
|
|
1016
|
-
immediate: {}
|
|
1019
|
+
immediate: {},
|
|
1020
|
+
forceStoreImmediate: {}
|
|
1017
1021
|
}
|
|
1018
1022
|
);
|
|
1019
1023
|
const iQueues = Object.keys(diffedItems.immediate);
|
|
@@ -1035,6 +1039,37 @@ class TaskHandler {
|
|
|
1035
1039
|
}
|
|
1036
1040
|
}
|
|
1037
1041
|
}
|
|
1042
|
+
const fsQueues = Object.keys(diffedItems.forceStoreImmediate);
|
|
1043
|
+
for (let i = 0; i < fsQueues.length; i++) {
|
|
1044
|
+
const queue = fsQueues[i];
|
|
1045
|
+
const queueTasks = diffedItems.forceStoreImmediate[queue].map((task) => {
|
|
1046
|
+
const id = task.id ? {} : { id: this.databaseAdapter.generateId() };
|
|
1047
|
+
return { ...id, ...task, status: "processing", processing_started_at: /* @__PURE__ */ new Date() };
|
|
1048
|
+
});
|
|
1049
|
+
await this.taskStore.addTasksToScheduled(queueTasks);
|
|
1050
|
+
try {
|
|
1051
|
+
await this.messageQueue.addMessages(queue, queueTasks);
|
|
1052
|
+
} catch (mqError) {
|
|
1053
|
+
this.logger.error(`MQ write failed for forceStoreImmediate tasks, resetting to scheduled: ${mqError}`);
|
|
1054
|
+
const taskIds = queueTasks.map((t) => t.id).filter(Boolean);
|
|
1055
|
+
if (taskIds.length > 0) {
|
|
1056
|
+
await this.databaseAdapter.updateTasks(
|
|
1057
|
+
taskIds.map((id) => ({ id, updates: { status: "scheduled" } }))
|
|
1058
|
+
).catch((resetErr) => {
|
|
1059
|
+
this.logger.error(`Failed to reset tasks to scheduled after MQ failure: ${resetErr}`);
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
throw mqError;
|
|
1063
|
+
}
|
|
1064
|
+
if (this.lifecycleProvider?.onTaskScheduled) {
|
|
1065
|
+
for (const task of queueTasks) {
|
|
1066
|
+
this.emitLifecycleEvent(
|
|
1067
|
+
this.lifecycleProvider.onTaskScheduled,
|
|
1068
|
+
this.buildTaskContext(task)
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1038
1073
|
const fQueues = Object.keys(diffedItems.future);
|
|
1039
1074
|
for (let i = 0; i < fQueues.length; i++) {
|
|
1040
1075
|
const queue = fQueues[i];
|