@supergrowthai/tq 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +138 -0
  2. package/dist/{PrismaAdapter-D-Bjaonm.cjs → PrismaAdapter-CT8dxOZX.cjs} +51 -3
  3. package/dist/PrismaAdapter-CT8dxOZX.cjs.map +1 -0
  4. package/dist/{PrismaAdapter-Kp4A4VHb.js → PrismaAdapter-Z2vLslDJ.js} +51 -3
  5. package/dist/PrismaAdapter-Z2vLslDJ.js.map +1 -0
  6. package/dist/adapters/index.cjs +1 -1
  7. package/dist/adapters/index.mjs +1 -1
  8. package/dist/core/Actions.cjs +13 -0
  9. package/dist/core/Actions.cjs.map +1 -1
  10. package/dist/core/Actions.mjs +13 -0
  11. package/dist/core/Actions.mjs.map +1 -1
  12. package/dist/index.cjs +603 -128
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.mjs +609 -134
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/src/adapters/ITaskStorageAdapter.d.cts +12 -0
  17. package/dist/src/adapters/ITaskStorageAdapter.d.ts +12 -0
  18. package/dist/src/adapters/InMemoryAdapter.d.cts +26 -1
  19. package/dist/src/adapters/InMemoryAdapter.d.ts +26 -1
  20. package/dist/src/adapters/MongoDbAdapter.d.cts +29 -2
  21. package/dist/src/adapters/MongoDbAdapter.d.ts +29 -2
  22. package/dist/src/adapters/PrismaAdapter.d.cts +36 -2
  23. package/dist/src/adapters/PrismaAdapter.d.ts +36 -2
  24. package/dist/src/adapters/index.d.cts +1 -1
  25. package/dist/src/adapters/index.d.ts +1 -1
  26. package/dist/src/core/Actions.d.cts +5 -0
  27. package/dist/src/core/Actions.d.ts +5 -0
  28. package/dist/src/core/TaskHandler.d.cts +22 -2
  29. package/dist/src/core/TaskHandler.d.ts +22 -2
  30. package/dist/src/core/TaskRunner.d.cts +10 -1
  31. package/dist/src/core/TaskRunner.d.ts +10 -1
  32. package/dist/src/core/lifecycle.d.cts +133 -0
  33. package/dist/src/core/lifecycle.d.ts +133 -0
  34. package/dist/src/index.d.cts +2 -0
  35. package/dist/src/index.d.ts +2 -0
  36. package/dist/src/providers/ConsoleHealthProvider.d.cts +47 -0
  37. package/dist/src/providers/ConsoleHealthProvider.d.ts +47 -0
  38. package/dist/src/providers/index.d.cts +1 -0
  39. package/dist/src/providers/index.d.ts +1 -0
  40. package/dist/src/utils/disposable-lock.d.cts +39 -0
  41. package/dist/src/utils/disposable-lock.d.ts +39 -0
  42. package/package.json +6 -6
  43. package/dist/PrismaAdapter-D-Bjaonm.cjs.map +0 -1
  44. package/dist/PrismaAdapter-Kp4A4VHb.js.map +0 -1
package/README.md CHANGED
@@ -285,6 +285,144 @@ const taskHandler = new TaskHandler(
285
285
  );
286
286
  ```
287
287
 
288
+ ## Lifecycle Callbacks
289
+
290
+ Monitor task and worker lifecycle events for health checks, metrics collection, and observability:
291
+
292
+ ### Task Lifecycle Provider
293
+
294
+ Track individual task events:
295
+
296
+ ```typescript
297
+ import {ITaskLifecycleProvider, TaskContext, TaskTiming} from '@supergrowthai/tq';
298
+
299
+ const taskLifecycleProvider: ITaskLifecycleProvider = {
300
+ onTaskScheduled(ctx: TaskContext) {
301
+ console.log(`Task scheduled: ${ctx.task_type} (${ctx.task_id})`);
302
+ },
303
+
304
+ onTaskStarted(ctx: TaskContext & { started_at: Date; queued_duration_ms: number }) {
305
+ console.log(`Task started: ${ctx.task_id}, queued for ${ctx.queued_duration_ms}ms`);
306
+ },
307
+
308
+ onTaskCompleted(ctx: TaskContext & { timing: TaskTiming; result?: unknown }) {
309
+ console.log(`Task completed: ${ctx.task_id} in ${ctx.timing.processing_duration_ms}ms`);
310
+ },
311
+
312
+ onTaskFailed(ctx: TaskContext & { timing: TaskTiming; error: Error; will_retry: boolean }) {
313
+ console.error(`Task failed: ${ctx.task_id}, will_retry: ${ctx.will_retry}`);
314
+ },
315
+
316
+ onTaskExhausted(ctx: TaskContext & { timing: TaskTiming; error: Error; total_attempts: number }) {
317
+ console.error(`Task exhausted: ${ctx.task_id} after ${ctx.total_attempts} attempts`);
318
+ },
319
+
320
+ onTaskCancelled(ctx: TaskContext & { reason: string }) {
321
+ console.log(`Task cancelled: ${ctx.task_id}, reason: ${ctx.reason}`);
322
+ }
323
+ };
324
+ ```
325
+
326
+ ### Worker Lifecycle Provider
327
+
328
+ Track worker and batch events:
329
+
330
+ ```typescript
331
+ import {IWorkerLifecycleProvider, WorkerInfo, WorkerStats} from '@supergrowthai/tq';
332
+
333
+ const workerLifecycleProvider: IWorkerLifecycleProvider = {
334
+ onWorkerStarted(info: WorkerInfo) {
335
+ console.log(`Worker started: ${info.worker_id} on ${info.hostname}`);
336
+ },
337
+
338
+ onWorkerHeartbeat(info: WorkerInfo & { stats: WorkerStats; memory_usage_mb: number }) {
339
+ console.log(`Heartbeat: ${info.worker_id}, processed: ${info.stats.tasks_processed}`);
340
+ },
341
+
342
+ onWorkerStopped(info: WorkerInfo & { reason: string; final_stats: WorkerStats }) {
343
+ console.log(`Worker stopped: ${info.worker_id}, reason: ${info.reason}`);
344
+ },
345
+
346
+ onBatchStarted(info: WorkerInfo & { batch_size: number; task_types: string[] }) {
347
+ console.log(`Batch started: ${info.batch_size} tasks`);
348
+ },
349
+
350
+ onBatchCompleted(info: WorkerInfo & { batch_size: number; succeeded: number; failed: number }) {
351
+ console.log(`Batch completed: ${info.succeeded}/${info.batch_size} succeeded`);
352
+ }
353
+ };
354
+ ```
355
+
356
+ ### Using Lifecycle Providers
357
+
358
+ Pass lifecycle providers when creating TaskHandler:
359
+
360
+ ```typescript
361
+ import {TaskHandler, ConsoleHealthProvider} from '@supergrowthai/tq';
362
+
363
+ // Option 1: Use built-in ConsoleHealthProvider
364
+ const healthProvider = new ConsoleHealthProvider();
365
+
366
+ const taskHandler = new TaskHandler(
367
+ messageQueue,
368
+ taskQueue,
369
+ databaseAdapter,
370
+ cacheAdapter,
371
+ asyncTaskManager,
372
+ notificationProvider,
373
+ {
374
+ lifecycleProvider: healthProvider,
375
+ workerProvider: healthProvider,
376
+ lifecycle: {
377
+ mode: 'async', // 'sync' or 'async' (default: async)
378
+ heartbeat_interval_ms: 5000, // Worker heartbeat interval
379
+ include_payload: false // Include task payload in callbacks
380
+ }
381
+ }
382
+ );
383
+
384
+ // Option 2: Custom providers
385
+ const taskHandler = new TaskHandler(
386
+ messageQueue,
387
+ taskQueue,
388
+ databaseAdapter,
389
+ cacheAdapter,
390
+ asyncTaskManager,
391
+ notificationProvider,
392
+ {
393
+ lifecycleProvider: myTaskLifecycleProvider,
394
+ workerProvider: myWorkerLifecycleProvider,
395
+ lifecycle: {
396
+ mode: 'sync' // Callbacks block task processing
397
+ }
398
+ }
399
+ );
400
+ ```
401
+
402
+ ### TaskContext Properties
403
+
404
+ | Property | Type | Description |
405
+ |--------------|-------------------------|----------------------------------|
406
+ | task_id | string | Unique task identifier |
407
+ | task_hash | string? | Optional deduplication hash |
408
+ | task_type | string | Type of the task |
409
+ | queue_id | string | Queue the task belongs to |
410
+ | payload | Record<string, unknown> | Task payload |
411
+ | attempt | number | Current attempt number |
412
+ | max_retries | number | Maximum retry attempts |
413
+ | scheduled_at | Date | When task was scheduled |
414
+ | worker_id | string? | ID of worker processing the task |
415
+
416
+ ### WorkerInfo Properties
417
+
418
+ | Property | Type | Description |
419
+ |----------------|----------|--------------------------|
420
+ | worker_id | string | Unique worker identifier |
421
+ | hostname | string | Machine hostname |
422
+ | pid | number | Process ID |
423
+ | started_at | Date | When worker started |
424
+ | enabled_queues | string[] | Queues being processed |
425
+
288
426
  ## Error Handling and Retries
289
427
 
290
428
  ```typescript
@@ -1,13 +1,29 @@
1
1
  "use strict";
2
2
  const mongodb = require("mongodb");
3
3
  const client = require("./client-DgdG7pT6.cjs");
4
- new client.Logger("MongoDbAdapter", client.LogLevel.INFO);
4
+ const logger$1 = new client.Logger("MongoDbAdapter", client.LogLevel.INFO);
5
5
  const TWO_DAYS_MS$1 = 2 * 24 * 60 * 60 * 1e3;
6
6
  function toPublicTask({ _id, ...rest }) {
7
7
  return { ...rest, id: _id };
8
8
  }
9
9
  class MongoDbAdapter {
10
10
  constructor() {
11
+ this.lifecycleMode = "async";
12
+ }
13
+ setLifecycleConfig(config) {
14
+ this.lifecycleProvider = config.lifecycleProvider;
15
+ this.lifecycleMode = config.mode || "async";
16
+ }
17
+ emitLifecycleEvent(callback, ctx) {
18
+ if (!callback) return;
19
+ try {
20
+ const result = callback(ctx);
21
+ if (result instanceof Promise) {
22
+ result.catch((err) => logger$1.error(`[TQ] Lifecycle callback error: ${err}`));
23
+ }
24
+ } catch (err) {
25
+ logger$1.error(`[TQ] Lifecycle callback error: ${err}`);
26
+ }
11
27
  }
12
28
  async addTasksToScheduled(tasks) {
13
29
  if (!tasks.length) return [];
@@ -183,11 +199,27 @@ class MongoDbAdapter {
183
199
  class InMemoryAdapter {
184
200
  constructor() {
185
201
  this.scheduledTasks = /* @__PURE__ */ new Map();
202
+ this.lifecycleMode = "async";
203
+ }
204
+ setLifecycleConfig(config) {
205
+ this.lifecycleProvider = config.lifecycleProvider;
206
+ this.lifecycleMode = config.mode || "async";
207
+ }
208
+ emitLifecycleEvent(callback, ctx) {
209
+ if (!callback) return;
210
+ try {
211
+ const result = callback(ctx);
212
+ if (result instanceof Promise) {
213
+ result.catch((err) => console.error(`[TQ] Lifecycle callback error: ${err}`));
214
+ }
215
+ } catch (err) {
216
+ console.error(`[TQ] Lifecycle callback error: ${err}`);
217
+ }
186
218
  }
187
219
  async addTasksToScheduled(tasks) {
188
220
  const addedTasks = tasks.map((task) => {
189
221
  const id = task.id || this.generateId();
190
- const taskWithId = { ...task };
222
+ const taskWithId = { ...task, id };
191
223
  this.scheduledTasks.set(id, taskWithId);
192
224
  return taskWithId;
193
225
  });
@@ -290,6 +322,22 @@ const TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1e3;
290
322
  class PrismaAdapter {
291
323
  constructor(config) {
292
324
  this.config = config;
325
+ this.lifecycleMode = "async";
326
+ }
327
+ setLifecycleConfig(config) {
328
+ this.lifecycleProvider = config.lifecycleProvider;
329
+ this.lifecycleMode = config.mode || "async";
330
+ }
331
+ emitLifecycleEvent(callback, ctx) {
332
+ if (!callback) return;
333
+ try {
334
+ const result = callback(ctx);
335
+ if (result instanceof Promise) {
336
+ result.catch((err) => logger.error(`[TQ] Lifecycle callback error: ${err}`));
337
+ }
338
+ } catch (err) {
339
+ logger.error(`[TQ] Lifecycle callback error: ${err}`);
340
+ }
293
341
  }
294
342
  get prismaClient() {
295
343
  return this.config.prismaClient;
@@ -441,4 +489,4 @@ class PrismaAdapter {
441
489
  exports.InMemoryAdapter = InMemoryAdapter;
442
490
  exports.MongoDbAdapter = MongoDbAdapter;
443
491
  exports.PrismaAdapter = PrismaAdapter;
444
- //# sourceMappingURL=PrismaAdapter-D-Bjaonm.cjs.map
492
+ //# sourceMappingURL=PrismaAdapter-CT8dxOZX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrismaAdapter-CT8dxOZX.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 await collection.bulkWrite(bulkOps);\n }\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 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 private get delegate(): PrismaClient[K] {\n return this.config.prismaClient[this.config.messageModel];\n }\n\n async addTasksToScheduled(tasks: CronTask<TId>[]): Promise<CronTask<TId>[]> {\n if (!tasks.length) return [];\n\n try {\n await this.delegate.createMany({\n data: tasks.map(task => ({\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 skipDuplicates: true\n });\n return tasks;\n } catch (error: unknown) {\n logger.warn(`Some tasks skipped due to duplicates: ${error}`);\n return tasks;\n }\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 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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"}
@@ -1,12 +1,28 @@
1
1
  import { ObjectId } from "mongodb";
2
2
  import { L as Logger, a as LogLevel } from "./client-BAiCkZv7.js";
3
- new Logger("MongoDbAdapter", LogLevel.INFO);
3
+ const logger$1 = new Logger("MongoDbAdapter", LogLevel.INFO);
4
4
  const TWO_DAYS_MS$1 = 2 * 24 * 60 * 60 * 1e3;
5
5
  function toPublicTask({ _id, ...rest }) {
6
6
  return { ...rest, id: _id };
7
7
  }
8
8
  class MongoDbAdapter {
9
9
  constructor() {
10
+ this.lifecycleMode = "async";
11
+ }
12
+ setLifecycleConfig(config) {
13
+ this.lifecycleProvider = config.lifecycleProvider;
14
+ this.lifecycleMode = config.mode || "async";
15
+ }
16
+ emitLifecycleEvent(callback, ctx) {
17
+ if (!callback) return;
18
+ try {
19
+ const result = callback(ctx);
20
+ if (result instanceof Promise) {
21
+ result.catch((err) => logger$1.error(`[TQ] Lifecycle callback error: ${err}`));
22
+ }
23
+ } catch (err) {
24
+ logger$1.error(`[TQ] Lifecycle callback error: ${err}`);
25
+ }
10
26
  }
11
27
  async addTasksToScheduled(tasks) {
12
28
  if (!tasks.length) return [];
@@ -182,11 +198,27 @@ class MongoDbAdapter {
182
198
  class InMemoryAdapter {
183
199
  constructor() {
184
200
  this.scheduledTasks = /* @__PURE__ */ new Map();
201
+ this.lifecycleMode = "async";
202
+ }
203
+ setLifecycleConfig(config) {
204
+ this.lifecycleProvider = config.lifecycleProvider;
205
+ this.lifecycleMode = config.mode || "async";
206
+ }
207
+ emitLifecycleEvent(callback, ctx) {
208
+ if (!callback) return;
209
+ try {
210
+ const result = callback(ctx);
211
+ if (result instanceof Promise) {
212
+ result.catch((err) => console.error(`[TQ] Lifecycle callback error: ${err}`));
213
+ }
214
+ } catch (err) {
215
+ console.error(`[TQ] Lifecycle callback error: ${err}`);
216
+ }
185
217
  }
186
218
  async addTasksToScheduled(tasks) {
187
219
  const addedTasks = tasks.map((task) => {
188
220
  const id = task.id || this.generateId();
189
- const taskWithId = { ...task };
221
+ const taskWithId = { ...task, id };
190
222
  this.scheduledTasks.set(id, taskWithId);
191
223
  return taskWithId;
192
224
  });
@@ -289,6 +321,22 @@ const TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1e3;
289
321
  class PrismaAdapter {
290
322
  constructor(config) {
291
323
  this.config = config;
324
+ this.lifecycleMode = "async";
325
+ }
326
+ setLifecycleConfig(config) {
327
+ this.lifecycleProvider = config.lifecycleProvider;
328
+ this.lifecycleMode = config.mode || "async";
329
+ }
330
+ emitLifecycleEvent(callback, ctx) {
331
+ if (!callback) return;
332
+ try {
333
+ const result = callback(ctx);
334
+ if (result instanceof Promise) {
335
+ result.catch((err) => logger.error(`[TQ] Lifecycle callback error: ${err}`));
336
+ }
337
+ } catch (err) {
338
+ logger.error(`[TQ] Lifecycle callback error: ${err}`);
339
+ }
292
340
  }
293
341
  get prismaClient() {
294
342
  return this.config.prismaClient;
@@ -442,4 +490,4 @@ export {
442
490
  MongoDbAdapter as M,
443
491
  PrismaAdapter as P
444
492
  };
445
- //# sourceMappingURL=PrismaAdapter-Kp4A4VHb.js.map
493
+ //# sourceMappingURL=PrismaAdapter-Z2vLslDJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrismaAdapter-Z2vLslDJ.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 await collection.bulkWrite(bulkOps);\n }\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 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 private get delegate(): PrismaClient[K] {\n return this.config.prismaClient[this.config.messageModel];\n }\n\n async addTasksToScheduled(tasks: CronTask<TId>[]): Promise<CronTask<TId>[]> {\n if (!tasks.length) return [];\n\n try {\n await this.delegate.createMany({\n data: tasks.map(task => ({\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 skipDuplicates: true\n });\n return tasks;\n } catch (error: unknown) {\n logger.warn(`Some tasks skipped due to duplicates: ${error}`);\n return tasks;\n }\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 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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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const PrismaAdapter = require("../PrismaAdapter-D-Bjaonm.cjs");
3
+ const PrismaAdapter = require("../PrismaAdapter-CT8dxOZX.cjs");
4
4
  exports.InMemoryAdapter = PrismaAdapter.InMemoryAdapter;
5
5
  exports.MongoDbAdapter = PrismaAdapter.MongoDbAdapter;
6
6
  exports.PrismaAdapter = PrismaAdapter.PrismaAdapter;
@@ -1,4 +1,4 @@
1
- import { I, M, P } from "../PrismaAdapter-Kp4A4VHb.js";
1
+ import { I, M, P } from "../PrismaAdapter-Z2vLslDJ.js";
2
2
  export {
3
3
  I as InMemoryAdapter,
4
4
  M as MongoDbAdapter,
@@ -90,6 +90,19 @@ class Actions {
90
90
  this.taskContexts.set(taskId, { task, actions: [] });
91
91
  logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);
92
92
  }
93
+ /**
94
+ * Check the result status for a specific task
95
+ * Returns 'success', 'fail', or 'pending' (no action recorded yet)
96
+ */
97
+ getTaskResultStatus(taskId) {
98
+ const context = this.taskContexts.get(taskId);
99
+ if (!context) return "pending";
100
+ for (const action of context.actions) {
101
+ if (action.type === "success") return "success";
102
+ if (action.type === "fail") return "fail";
103
+ }
104
+ return "pending";
105
+ }
93
106
  /**
94
107
  * Extract actions for a single task (used by async tasks)
95
108
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Actions.cjs","sources":["../../src/core/Actions.ts"],"sourcesContent":["import {ExecutorActions} from \"./base/interfaces\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {tId} from \"../utils/task-id-gen.js\";\nimport {CronTask} from \"../adapters\";\n\nconst logger = new Logger('Actions', LogLevel.INFO);\n\ninterface ActionEntry<ID = any> {\n type: 'success' | 'fail' | 'addTasks';\n timestamp: number;\n task?: CronTask<ID>; // The task passed to success/fail\n newTasks?: CronTask<ID>[]; // Tasks to add\n}\n\ninterface TaskContext<ID = any> {\n task: CronTask<ID> | null; // The task being executed (null for batch contexts)\n actions: ActionEntry<ID>[];\n}\n\nexport interface ActionResults<ID = any> {\n failedTasks: CronTask<ID>[];\n successTasks: CronTask<ID>[];\n newTasks: CronTask<ID>[];\n ignoredTasks: CronTask<ID>[];\n}\n\nexport class Actions<ID = any> implements ExecutorActions<ID> {\n private readonly taskRunnerId: string;\n private readonly taskContexts = new Map<string, TaskContext<ID>>();\n\n constructor(taskRunnerId: string) {\n this.taskRunnerId = taskRunnerId;\n }\n\n /**\n * Fork execution context for a specific task (for single-task executors)\n */\n forkForTask(task: CronTask<ID>): ExecutorActions<ID> {\n const taskId = tId(task);\n\n // Initialize context for this task\n const context: TaskContext<ID> = {task, actions: []};\n this.taskContexts.set(taskId, context);\n\n // Return a scoped actions object that tracks everything in this context\n return {\n fail: (t: CronTask<ID>) => {\n context.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task: t\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${tId(t)} (${t.type})`);\n },\n\n success: (t: CronTask<ID>) => {\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task: t\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${tId(t)} (${t.type})`);\n },\n\n addTasks: (tasks: CronTask<ID>[]) => {\n context.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n logger.info(`[${this.taskRunnerId}] Task ${taskId} adding ${tasks.length} new tasks`);\n }\n };\n }\n\n // For multi-task executors - they use the root Actions directly (no forking)\n fail(task: CronTask<ID>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context!.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${taskId} (${task.type})`);\n }\n\n success(task: CronTask<ID>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${taskId} (${task.type})`);\n }\n\n addTasks(tasks: CronTask<ID>[]): void {\n // For multi-task mode, store in a batch-specific context\n logger.info(`[${this.taskRunnerId}] Adding ${tasks.length} new tasks`);\n\n const batchKey = `__batch_${this.taskRunnerId}__`;\n let batchContext = this.taskContexts.get(batchKey);\n if (!batchContext) {\n batchContext = {task: null, actions: []};\n this.taskContexts.set(batchKey, batchContext);\n }\n batchContext.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n }\n\n addIgnoredTask(task: CronTask<ID>): void {\n const taskId = tId(task);\n this.taskContexts.set(taskId, {task, actions: []});\n logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);\n }\n\n /**\n * Extract actions for a single task (used by async tasks)\n */\n extractTaskActions(taskId: string): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: []\n };\n\n const context = this.taskContexts.get(taskId);\n if (!context) return results;\n\n if (context.actions.length === 0 && context.task) {\n // No actions = ignored task\n results.ignoredTasks.push(context.task);\n } else {\n // Process all actions\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n results.successTasks.push(action.task);\n // If marking a different task, remove its context\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(action.task);\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n\n this.taskContexts.delete(taskId);\n return results;\n }\n\n /**\n * Extract sync results including batch context (for sync processing)\n */\n extractSyncResults(excludeTaskIds: string[]): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: []\n };\n\n const excludeSet = new Set(excludeTaskIds);\n const batchKey = `__batch_${this.taskRunnerId}__`;\n\n // Process all task contexts except excluded ones\n for (const [taskId, context] of this.taskContexts) {\n if (excludeSet.has(taskId)) continue;\n\n if (taskId === batchKey) {\n // Batch context - only has addTasks\n for (const action of context.actions) {\n if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n } else {\n // Regular task context\n if (context.actions.length === 0 && context.task) {\n results.ignoredTasks.push(context.task);\n } else {\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n results.successTasks.push(action.task);\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(action.task);\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n }\n }\n\n // Clear processed contexts\n for (const [taskId] of this.taskContexts) {\n if (!excludeSet.has(taskId)) {\n this.taskContexts.delete(taskId);\n }\n }\n\n return results;\n }\n\n /**\n * Get all results (mainly for backward compatibility)\n */\n getResults(): ActionResults<ID> {\n return this.extractSyncResults([]);\n }\n}"],"names":["Logger","LogLevel","tId"],"mappings":"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"}
1
+ {"version":3,"file":"Actions.cjs","sources":["../../src/core/Actions.ts"],"sourcesContent":["import {ExecutorActions} from \"./base/interfaces\";\nimport {Logger, LogLevel} from \"@supergrowthai/utils\";\nimport {tId} from \"../utils/task-id-gen.js\";\nimport {CronTask} from \"../adapters\";\n\nconst logger = new Logger('Actions', LogLevel.INFO);\n\ninterface ActionEntry<ID = any> {\n type: 'success' | 'fail' | 'addTasks';\n timestamp: number;\n task?: CronTask<ID>; // The task passed to success/fail\n newTasks?: CronTask<ID>[]; // Tasks to add\n}\n\ninterface TaskContext<ID = any> {\n task: CronTask<ID> | null; // The task being executed (null for batch contexts)\n actions: ActionEntry<ID>[];\n}\n\nexport interface ActionResults<ID = any> {\n failedTasks: CronTask<ID>[];\n successTasks: CronTask<ID>[];\n newTasks: CronTask<ID>[];\n ignoredTasks: CronTask<ID>[];\n}\n\nexport class Actions<ID = any> implements ExecutorActions<ID> {\n private readonly taskRunnerId: string;\n private readonly taskContexts = new Map<string, TaskContext<ID>>();\n\n constructor(taskRunnerId: string) {\n this.taskRunnerId = taskRunnerId;\n }\n\n /**\n * Fork execution context for a specific task (for single-task executors)\n */\n forkForTask(task: CronTask<ID>): ExecutorActions<ID> {\n const taskId = tId(task);\n\n // Initialize context for this task\n const context: TaskContext<ID> = {task, actions: []};\n this.taskContexts.set(taskId, context);\n\n // Return a scoped actions object that tracks everything in this context\n return {\n fail: (t: CronTask<ID>) => {\n context.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task: t\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${tId(t)} (${t.type})`);\n },\n\n success: (t: CronTask<ID>) => {\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task: t\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${tId(t)} (${t.type})`);\n },\n\n addTasks: (tasks: CronTask<ID>[]) => {\n context.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n logger.info(`[${this.taskRunnerId}] Task ${taskId} adding ${tasks.length} new tasks`);\n }\n };\n }\n\n // For multi-task executors - they use the root Actions directly (no forking)\n fail(task: CronTask<ID>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context!.actions.push({\n type: 'fail',\n timestamp: Date.now(),\n task\n });\n logger.error(`[${this.taskRunnerId}] Task failed: ${taskId} (${task.type})`);\n }\n\n success(task: CronTask<ID>): void {\n const taskId = tId(task);\n let context = this.taskContexts.get(taskId);\n if (!context) {\n context = {task, actions: []};\n this.taskContexts.set(taskId, context);\n }\n\n context.actions.push({\n type: 'success',\n timestamp: Date.now(),\n task\n });\n logger.info(`[${this.taskRunnerId}] Task succeeded: ${taskId} (${task.type})`);\n }\n\n addTasks(tasks: CronTask<ID>[]): void {\n // For multi-task mode, store in a batch-specific context\n logger.info(`[${this.taskRunnerId}] Adding ${tasks.length} new tasks`);\n\n const batchKey = `__batch_${this.taskRunnerId}__`;\n let batchContext = this.taskContexts.get(batchKey);\n if (!batchContext) {\n batchContext = {task: null, actions: []};\n this.taskContexts.set(batchKey, batchContext);\n }\n batchContext.actions.push({\n type: 'addTasks',\n timestamp: Date.now(),\n newTasks: tasks\n });\n }\n\n addIgnoredTask(task: CronTask<ID>): void {\n const taskId = tId(task);\n this.taskContexts.set(taskId, {task, actions: []});\n logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);\n }\n\n /**\n * Check the result status for a specific task\n * Returns 'success', 'fail', or 'pending' (no action recorded yet)\n */\n getTaskResultStatus(taskId: string): 'success' | 'fail' | 'pending' {\n const context = this.taskContexts.get(taskId);\n if (!context) return 'pending';\n\n for (const action of context.actions) {\n if (action.type === 'success') return 'success';\n if (action.type === 'fail') return 'fail';\n }\n return 'pending';\n }\n\n /**\n * Extract actions for a single task (used by async tasks)\n */\n extractTaskActions(taskId: string): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: []\n };\n\n const context = this.taskContexts.get(taskId);\n if (!context) return results;\n\n if (context.actions.length === 0 && context.task) {\n // No actions = ignored task\n results.ignoredTasks.push(context.task);\n } else {\n // Process all actions\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n results.successTasks.push(action.task);\n // If marking a different task, remove its context\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(action.task);\n const targetTaskId = tId(action.task);\n if (targetTaskId !== taskId) {\n this.taskContexts.delete(targetTaskId);\n }\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n\n this.taskContexts.delete(taskId);\n return results;\n }\n\n /**\n * Extract sync results including batch context (for sync processing)\n */\n extractSyncResults(excludeTaskIds: string[]): ActionResults<ID> {\n const results: ActionResults<ID> = {\n failedTasks: [],\n successTasks: [],\n newTasks: [],\n ignoredTasks: []\n };\n\n const excludeSet = new Set(excludeTaskIds);\n const batchKey = `__batch_${this.taskRunnerId}__`;\n\n // Process all task contexts except excluded ones\n for (const [taskId, context] of this.taskContexts) {\n if (excludeSet.has(taskId)) continue;\n\n if (taskId === batchKey) {\n // Batch context - only has addTasks\n for (const action of context.actions) {\n if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n } else {\n // Regular task context\n if (context.actions.length === 0 && context.task) {\n results.ignoredTasks.push(context.task);\n } else {\n for (const action of context.actions) {\n if (action.type === 'success' && action.task) {\n results.successTasks.push(action.task);\n } else if (action.type === 'fail' && action.task) {\n results.failedTasks.push(action.task);\n } else if (action.type === 'addTasks' && action.newTasks) {\n results.newTasks.push(...action.newTasks);\n }\n }\n }\n }\n }\n\n // Clear processed contexts\n for (const [taskId] of this.taskContexts) {\n if (!excludeSet.has(taskId)) {\n this.taskContexts.delete(taskId);\n }\n }\n\n return results;\n }\n\n /**\n * Get all results (mainly for backward compatibility)\n */\n getResults(): ActionResults<ID> {\n return this.extractSyncResults([]);\n }\n}"],"names":["Logger","LogLevel","tId"],"mappings":"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"}
@@ -88,6 +88,19 @@ class Actions {
88
88
  this.taskContexts.set(taskId, { task, actions: [] });
89
89
  logger.warn(`[${this.taskRunnerId}] Task ignored: ${taskId} (${task.type})`);
90
90
  }
91
+ /**
92
+ * Check the result status for a specific task
93
+ * Returns 'success', 'fail', or 'pending' (no action recorded yet)
94
+ */
95
+ getTaskResultStatus(taskId) {
96
+ const context = this.taskContexts.get(taskId);
97
+ if (!context) return "pending";
98
+ for (const action of context.actions) {
99
+ if (action.type === "success") return "success";
100
+ if (action.type === "fail") return "fail";
101
+ }
102
+ return "pending";
103
+ }
91
104
  /**
92
105
  * Extract actions for a single task (used by async tasks)
93
106
  */