@supergrowthai/tq 1.0.4 → 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 +7 -7
  43. package/dist/PrismaAdapter-D-Bjaonm.cjs.map +0 -1
  44. package/dist/PrismaAdapter-Kp4A4VHb.js.map +0 -1
@@ -1,7 +1,32 @@
1
- import { ITaskStorageAdapter } from './ITaskStorageAdapter';
1
+ import { ITaskStorageAdapter, TaskStorageLifecycleConfig } from './ITaskStorageAdapter';
2
2
  import { CronTask } from './types';
3
+ /**
4
+ * In-memory task storage adapter for @supergrowthai/tq.
5
+ *
6
+ * @description Stores scheduled tasks in memory using a Map.
7
+ * Data is lost on process restart - use for development and testing only.
8
+ *
9
+ * @use-case Development, testing, and prototyping
10
+ * @multi-instance NOT SAFE - data is not shared between processes
11
+ * @persistence NONE - all tasks lost on restart
12
+ *
13
+ * @features
14
+ * - Fast in-memory operations
15
+ * - Simple cleanup implementation
16
+ * - Auto-generated string IDs
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const adapter = new InMemoryAdapter();
21
+ * const taskHandler = new TaskHandler(queue, taskQueue, adapter, cache);
22
+ * ```
23
+ */
3
24
  declare class InMemoryAdapter implements ITaskStorageAdapter<string> {
4
25
  private scheduledTasks;
26
+ private lifecycleProvider?;
27
+ private lifecycleMode;
28
+ setLifecycleConfig(config: TaskStorageLifecycleConfig): void;
29
+ private emitLifecycleEvent;
5
30
  addTasksToScheduled(tasks: CronTask<string>[]): Promise<CronTask<string>[]>;
6
31
  getMatureTasks(timestamp: number): Promise<CronTask<string>[]>;
7
32
  markTasksAsProcessing(tasks: CronTask<string>[], processingStartedAt: Date): Promise<void>;
@@ -1,11 +1,38 @@
1
1
  import { Collection, ObjectId } from 'mongodb';
2
- import { ITaskStorageAdapter } from './ITaskStorageAdapter.js';
2
+ import { ITaskStorageAdapter, TaskStorageLifecycleConfig } from './ITaskStorageAdapter.js';
3
3
  import { CronTask } from './types.js';
4
4
  /**
5
- * MongoDB implementation of IDatabaseAdapter
5
+ * MongoDB task storage adapter for @supergrowthai/tq.
6
+ *
7
+ * @description Persists scheduled tasks to MongoDB collection with status tracking.
8
+ * Uses application-level locking designed for single-instance deployments.
9
+ *
10
+ * @use-case Single-instance production deployments
11
+ * @multi-instance NOT SAFE - designed for single-instance use.
12
+ * For multi-instance deployments, implement a distributed locking strategy
13
+ * or use a Kinesis-based solution with Redis lock provider.
14
+ * @persistence Full - tasks stored in MongoDB until processed/expired
15
+ * @requires MongoDB connection via abstract `collection` getter
16
+ *
17
+ * @features
18
+ * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset
19
+ * - Bulk operations for efficiency
20
+ * - Task expiration cleanup
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * class MyTaskStorage extends MongoDbAdapter {
25
+ * get collection() { return db.collection('scheduled_tasks'); }
26
+ * }
27
+ * const adapter = new MyTaskStorage();
28
+ * ```
6
29
  */
7
30
  export declare abstract class MongoDbAdapter implements ITaskStorageAdapter<ObjectId> {
31
+ private lifecycleProvider?;
32
+ private lifecycleMode;
8
33
  protected constructor();
34
+ setLifecycleConfig(config: TaskStorageLifecycleConfig): void;
35
+ private emitLifecycleEvent;
9
36
  abstract get collection(): Promise<Collection<Omit<CronTask<ObjectId>, 'id'> & {
10
37
  _id?: ObjectId;
11
38
  }>>;
@@ -1,11 +1,38 @@
1
1
  import { Collection, ObjectId } from 'mongodb';
2
- import { ITaskStorageAdapter } from './ITaskStorageAdapter.js';
2
+ import { ITaskStorageAdapter, TaskStorageLifecycleConfig } from './ITaskStorageAdapter.js';
3
3
  import { CronTask } from './types.js';
4
4
  /**
5
- * MongoDB implementation of IDatabaseAdapter
5
+ * MongoDB task storage adapter for @supergrowthai/tq.
6
+ *
7
+ * @description Persists scheduled tasks to MongoDB collection with status tracking.
8
+ * Uses application-level locking designed for single-instance deployments.
9
+ *
10
+ * @use-case Single-instance production deployments
11
+ * @multi-instance NOT SAFE - designed for single-instance use.
12
+ * For multi-instance deployments, implement a distributed locking strategy
13
+ * or use a Kinesis-based solution with Redis lock provider.
14
+ * @persistence Full - tasks stored in MongoDB until processed/expired
15
+ * @requires MongoDB connection via abstract `collection` getter
16
+ *
17
+ * @features
18
+ * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset
19
+ * - Bulk operations for efficiency
20
+ * - Task expiration cleanup
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * class MyTaskStorage extends MongoDbAdapter {
25
+ * get collection() { return db.collection('scheduled_tasks'); }
26
+ * }
27
+ * const adapter = new MyTaskStorage();
28
+ * ```
6
29
  */
7
30
  export declare abstract class MongoDbAdapter implements ITaskStorageAdapter<ObjectId> {
31
+ private lifecycleProvider?;
32
+ private lifecycleMode;
8
33
  protected constructor();
34
+ setLifecycleConfig(config: TaskStorageLifecycleConfig): void;
35
+ private emitLifecycleEvent;
9
36
  abstract get collection(): Promise<Collection<Omit<CronTask<ObjectId>, 'id'> & {
10
37
  _id?: ObjectId;
11
38
  }>>;
@@ -1,4 +1,4 @@
1
- import { ITaskStorageAdapter } from './ITaskStorageAdapter.js';
1
+ import { ITaskStorageAdapter, TaskStorageLifecycleConfig } from './ITaskStorageAdapter.js';
2
2
  import { CronTask } from './types.js';
3
3
  import { PrismaClient } from '@prisma/client/extension';
4
4
  /** A Prisma client that is guaranteed to have model delegate K. */
@@ -11,10 +11,42 @@ type EntityOf<D> = D extends {
11
11
  } ? U : D extends {
12
12
  findMany(args?: any): Promise<(infer U)[]>;
13
13
  } ? U : never;
14
- /** Compile-time guard: models entity must be compatible with the shape you require. */
14
+ /** Compile-time guard: model's entity must be compatible with the shape you require. */
15
15
  type EnsureModelShape<Delegate, Needed> = EntityOf<Delegate> extends Needed ? unknown : never;
16
+ /**
17
+ * Prisma task storage adapter for @supergrowthai/tq.
18
+ *
19
+ * @description Persists scheduled tasks to any Prisma model with status tracking.
20
+ * Uses application-level locking designed for single-instance deployments.
21
+ *
22
+ * @use-case Single-instance production deployments with Prisma ORM
23
+ * @multi-instance NOT SAFE - designed for single-instance use.
24
+ * For multi-instance deployments, implement a distributed locking strategy
25
+ * or use a Kinesis-based solution with Redis lock provider.
26
+ * @persistence Full - tasks stored in database until processed/expired
27
+ * @requires Prisma client with a model matching CronTask structure
28
+ *
29
+ * @features
30
+ * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset
31
+ * - Transaction support for batch updates
32
+ * - Task expiration cleanup
33
+ *
34
+ * @typeParam TId - The ID type (string, number, etc.)
35
+ * @typeParam K - The Prisma model key (e.g. 'scheduledTask')
36
+ * @typeParam Msg - The task type extending CronTask<TId>
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const adapter = new PrismaAdapter({
41
+ * prismaClient: prisma,
42
+ * messageModel: 'scheduledTask'
43
+ * });
44
+ * ```
45
+ */
16
46
  export declare class PrismaAdapter<TId = any, K extends keyof PrismaClient = never, Msg extends CronTask<TId> = CronTask<TId>> implements ITaskStorageAdapter<TId> {
17
47
  private config;
48
+ private lifecycleProvider?;
49
+ private lifecycleMode;
18
50
  constructor(config: {
19
51
  prismaClient: ClientWithModel<K>;
20
52
  messageModel: K;
@@ -28,6 +60,8 @@ export declare class PrismaAdapter<TId = any, K extends keyof PrismaClient = nev
28
60
  id: TId;
29
61
  } ? unknown : never);
30
62
  });
63
+ setLifecycleConfig(config: TaskStorageLifecycleConfig): void;
64
+ private emitLifecycleEvent;
31
65
  get prismaClient(): PrismaClient;
32
66
  get taskTableName(): string;
33
67
  private get delegate();
@@ -1,4 +1,4 @@
1
- import { ITaskStorageAdapter } from './ITaskStorageAdapter.js';
1
+ import { ITaskStorageAdapter, TaskStorageLifecycleConfig } from './ITaskStorageAdapter.js';
2
2
  import { CronTask } from './types.js';
3
3
  import { PrismaClient } from '@prisma/client/extension';
4
4
  /** A Prisma client that is guaranteed to have model delegate K. */
@@ -11,10 +11,42 @@ type EntityOf<D> = D extends {
11
11
  } ? U : D extends {
12
12
  findMany(args?: any): Promise<(infer U)[]>;
13
13
  } ? U : never;
14
- /** Compile-time guard: models entity must be compatible with the shape you require. */
14
+ /** Compile-time guard: model's entity must be compatible with the shape you require. */
15
15
  type EnsureModelShape<Delegate, Needed> = EntityOf<Delegate> extends Needed ? unknown : never;
16
+ /**
17
+ * Prisma task storage adapter for @supergrowthai/tq.
18
+ *
19
+ * @description Persists scheduled tasks to any Prisma model with status tracking.
20
+ * Uses application-level locking designed for single-instance deployments.
21
+ *
22
+ * @use-case Single-instance production deployments with Prisma ORM
23
+ * @multi-instance NOT SAFE - designed for single-instance use.
24
+ * For multi-instance deployments, implement a distributed locking strategy
25
+ * or use a Kinesis-based solution with Redis lock provider.
26
+ * @persistence Full - tasks stored in database until processed/expired
27
+ * @requires Prisma client with a model matching CronTask structure
28
+ *
29
+ * @features
30
+ * - Stale task recovery: tasks stuck in 'processing' for >2 days are reset
31
+ * - Transaction support for batch updates
32
+ * - Task expiration cleanup
33
+ *
34
+ * @typeParam TId - The ID type (string, number, etc.)
35
+ * @typeParam K - The Prisma model key (e.g. 'scheduledTask')
36
+ * @typeParam Msg - The task type extending CronTask<TId>
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const adapter = new PrismaAdapter({
41
+ * prismaClient: prisma,
42
+ * messageModel: 'scheduledTask'
43
+ * });
44
+ * ```
45
+ */
16
46
  export declare class PrismaAdapter<TId = any, K extends keyof PrismaClient = never, Msg extends CronTask<TId> = CronTask<TId>> implements ITaskStorageAdapter<TId> {
17
47
  private config;
48
+ private lifecycleProvider?;
49
+ private lifecycleMode;
18
50
  constructor(config: {
19
51
  prismaClient: ClientWithModel<K>;
20
52
  messageModel: K;
@@ -28,6 +60,8 @@ export declare class PrismaAdapter<TId = any, K extends keyof PrismaClient = nev
28
60
  id: TId;
29
61
  } ? unknown : never);
30
62
  });
63
+ setLifecycleConfig(config: TaskStorageLifecycleConfig): void;
64
+ private emitLifecycleEvent;
31
65
  get prismaClient(): PrismaClient;
32
66
  get taskTableName(): string;
33
67
  private get delegate();
@@ -1,5 +1,5 @@
1
1
  export type { CronTask } from './types.js';
2
- export type { ITaskStorageAdapter } from './ITaskStorageAdapter.js';
2
+ export type { ITaskStorageAdapter, TaskStorageLifecycleConfig } from './ITaskStorageAdapter.js';
3
3
  export { MongoDbAdapter } from './MongoDbAdapter.js';
4
4
  export { InMemoryAdapter } from './InMemoryAdapter.js';
5
5
  export { PrismaAdapter } from './PrismaAdapter.js';
@@ -1,5 +1,5 @@
1
1
  export type { CronTask } from './types.js';
2
- export type { ITaskStorageAdapter } from './ITaskStorageAdapter.js';
2
+ export type { ITaskStorageAdapter, TaskStorageLifecycleConfig } from './ITaskStorageAdapter.js';
3
3
  export { MongoDbAdapter } from './MongoDbAdapter.js';
4
4
  export { InMemoryAdapter } from './InMemoryAdapter.js';
5
5
  export { PrismaAdapter } from './PrismaAdapter.js';
@@ -18,6 +18,11 @@ export declare class Actions<ID = any> implements ExecutorActions<ID> {
18
18
  success(task: CronTask<ID>): void;
19
19
  addTasks(tasks: CronTask<ID>[]): void;
20
20
  addIgnoredTask(task: CronTask<ID>): void;
21
+ /**
22
+ * Check the result status for a specific task
23
+ * Returns 'success', 'fail', or 'pending' (no action recorded yet)
24
+ */
25
+ getTaskResultStatus(taskId: string): 'success' | 'fail' | 'pending';
21
26
  /**
22
27
  * Extract actions for a single task (used by async tasks)
23
28
  */
@@ -18,6 +18,11 @@ export declare class Actions<ID = any> implements ExecutorActions<ID> {
18
18
  success(task: CronTask<ID>): void;
19
19
  addTasks(tasks: CronTask<ID>[]): void;
20
20
  addIgnoredTask(task: CronTask<ID>): void;
21
+ /**
22
+ * Check the result status for a specific task
23
+ * Returns 'success', 'fail', or 'pending' (no action recorded yet)
24
+ */
25
+ getTaskResultStatus(taskId: string): 'success' | 'fail' | 'pending';
21
26
  /**
22
27
  * Extract actions for a single task (used by async tasks)
23
28
  */
@@ -5,6 +5,7 @@ import { CacheProvider } from 'memoose-js';
5
5
  import { TaskQueuesManager } from './TaskQueuesManager';
6
6
  import { IAsyncTaskManager } from './async/async-task-manager';
7
7
  import { ITaskNotificationProvider } from './ITaskNotificationProvider.js';
8
+ import { TaskHandlerConfig } from './lifecycle.js';
8
9
  export declare class TaskHandler<ID> {
9
10
  private messageQueue;
10
11
  private taskQueuesManager;
@@ -16,8 +17,18 @@ export declare class TaskHandler<ID> {
16
17
  private taskRunner;
17
18
  private readonly taskStore;
18
19
  private matureTaskTimer;
20
+ private heartbeatTimer;
21
+ private readonly config;
22
+ private readonly workerId;
23
+ private readonly workerStartedAt;
24
+ private enabledQueues;
25
+ private workerStarted;
26
+ private workerStats;
27
+ private totalProcessingMs;
19
28
  private readonly queueStats;
20
- constructor(messageQueue: IMessageQueue<ID>, taskQueuesManager: TaskQueuesManager<ID>, databaseAdapter: ITaskStorageAdapter<ID>, cacheAdapter: CacheProvider<any>, asyncTaskManager?: IAsyncTaskManager<ID> | undefined, notificationProvider?: ITaskNotificationProvider | undefined);
29
+ constructor(messageQueue: IMessageQueue<ID>, taskQueuesManager: TaskQueuesManager<ID>, databaseAdapter: ITaskStorageAdapter<ID>, cacheAdapter: CacheProvider<any>, asyncTaskManager?: IAsyncTaskManager<ID> | undefined, notificationProvider?: ITaskNotificationProvider | undefined, config?: TaskHandlerConfig);
30
+ private get lifecycleProvider();
31
+ private get workerProvider();
21
32
  addTasks(tasks: CronTask<ID>[]): Promise<void>;
22
33
  postProcessTasks({ failedTasks: failedTasksRaw, newTasks, successTasks }: ProcessedTaskResult<ID>): Promise<void>;
23
34
  startConsumingTasks(streamName: QueueName, abortSignal?: AbortSignal): Promise<{
@@ -27,8 +38,17 @@ export declare class TaskHandler<ID> {
27
38
  asyncTasks: never[] | import('./TaskRunner.js').AsyncTask<ID>[];
28
39
  ignoredTasks: never[] | CronTask<ID>[];
29
40
  }>;
30
- processMatureTasks(abortSignal?: AbortSignal): void;
31
41
  taskProcessServer(abortSignal?: AbortSignal): void;
42
+ private buildWorkerInfo;
43
+ private emitWorkerStarted;
44
+ private emitWorkerStopped;
45
+ private emitWorkerHeartbeat;
46
+ private startHeartbeat;
47
+ private stopHeartbeat;
48
+ private updateWorkerStats;
49
+ private emitLifecycleEvent;
50
+ processMatureTasks(abortSignal?: AbortSignal): void;
51
+ private buildTaskContext;
32
52
  processBatch(queueId: QueueName, processor: MessageConsumer<ID>, limit?: number, abortSignal?: AbortSignal): Promise<void>;
33
53
  private trackDiscardedTasks;
34
54
  private getRetryCount;
@@ -5,6 +5,7 @@ import { CacheProvider } from 'memoose-js';
5
5
  import { TaskQueuesManager } from './TaskQueuesManager';
6
6
  import { IAsyncTaskManager } from './async/async-task-manager';
7
7
  import { ITaskNotificationProvider } from './ITaskNotificationProvider.js';
8
+ import { TaskHandlerConfig } from './lifecycle.js';
8
9
  export declare class TaskHandler<ID> {
9
10
  private messageQueue;
10
11
  private taskQueuesManager;
@@ -16,8 +17,18 @@ export declare class TaskHandler<ID> {
16
17
  private taskRunner;
17
18
  private readonly taskStore;
18
19
  private matureTaskTimer;
20
+ private heartbeatTimer;
21
+ private readonly config;
22
+ private readonly workerId;
23
+ private readonly workerStartedAt;
24
+ private enabledQueues;
25
+ private workerStarted;
26
+ private workerStats;
27
+ private totalProcessingMs;
19
28
  private readonly queueStats;
20
- constructor(messageQueue: IMessageQueue<ID>, taskQueuesManager: TaskQueuesManager<ID>, databaseAdapter: ITaskStorageAdapter<ID>, cacheAdapter: CacheProvider<any>, asyncTaskManager?: IAsyncTaskManager<ID> | undefined, notificationProvider?: ITaskNotificationProvider | undefined);
29
+ constructor(messageQueue: IMessageQueue<ID>, taskQueuesManager: TaskQueuesManager<ID>, databaseAdapter: ITaskStorageAdapter<ID>, cacheAdapter: CacheProvider<any>, asyncTaskManager?: IAsyncTaskManager<ID> | undefined, notificationProvider?: ITaskNotificationProvider | undefined, config?: TaskHandlerConfig);
30
+ private get lifecycleProvider();
31
+ private get workerProvider();
21
32
  addTasks(tasks: CronTask<ID>[]): Promise<void>;
22
33
  postProcessTasks({ failedTasks: failedTasksRaw, newTasks, successTasks }: ProcessedTaskResult<ID>): Promise<void>;
23
34
  startConsumingTasks(streamName: QueueName, abortSignal?: AbortSignal): Promise<{
@@ -27,8 +38,17 @@ export declare class TaskHandler<ID> {
27
38
  asyncTasks: never[] | import('./TaskRunner.js').AsyncTask<ID>[];
28
39
  ignoredTasks: never[] | CronTask<ID>[];
29
40
  }>;
30
- processMatureTasks(abortSignal?: AbortSignal): void;
31
41
  taskProcessServer(abortSignal?: AbortSignal): void;
42
+ private buildWorkerInfo;
43
+ private emitWorkerStarted;
44
+ private emitWorkerStopped;
45
+ private emitWorkerHeartbeat;
46
+ private startHeartbeat;
47
+ private stopHeartbeat;
48
+ private updateWorkerStats;
49
+ private emitLifecycleEvent;
50
+ processMatureTasks(abortSignal?: AbortSignal): void;
51
+ private buildTaskContext;
32
52
  processBatch(queueId: QueueName, processor: MessageConsumer<ID>, limit?: number, abortSignal?: AbortSignal): Promise<void>;
33
53
  private trackDiscardedTasks;
34
54
  private getRetryCount;
@@ -6,6 +6,7 @@ import { CacheProvider } from 'memoose-js';
6
6
  import { TaskQueuesManager } from './TaskQueuesManager';
7
7
  import { TaskStore } from './TaskStore';
8
8
  import { IAsyncTaskManager } from './async/async-task-manager';
9
+ import { ITaskLifecycleProvider, TaskHandlerLifecycleConfig } from './lifecycle.js';
9
10
  export interface AsyncTask<ID> {
10
11
  task: CronTask<ID>;
11
12
  promise: Promise<void>;
@@ -17,10 +18,18 @@ export declare class TaskRunner<ID> {
17
18
  private taskQueue;
18
19
  private taskStore;
19
20
  private generateId;
21
+ private lifecycleProvider?;
22
+ private lifecycleConfig?;
20
23
  private readonly logger;
21
24
  private lockManager;
22
- constructor(messageQueue: IMessageQueue<ID>, taskQueue: TaskQueuesManager<ID>, taskStore: TaskStore<ID>, cacheProvider: CacheProvider<any>, generateId: () => ID);
25
+ private readonly taskStartTimes;
26
+ constructor(messageQueue: IMessageQueue<ID>, taskQueue: TaskQueuesManager<ID>, taskStore: TaskStore<ID>, cacheProvider: CacheProvider<any>, generateId: () => ID, lifecycleProvider?: ITaskLifecycleProvider | undefined, lifecycleConfig?: TaskHandlerLifecycleConfig | undefined);
23
27
  run(taskRunnerId: string, tasksRaw: Array<CronTask<ID>>, asyncTaskManager?: IAsyncTaskManager, abortSignal?: AbortSignal): Promise<ActionResults<ID> & {
24
28
  asyncTasks: AsyncTask<ID>[];
25
29
  }>;
30
+ private emitLifecycleEvent;
31
+ private buildTaskContext;
32
+ private emitTaskStarted;
33
+ private emitTaskCompleted;
34
+ private emitTaskFailed;
26
35
  }
@@ -6,6 +6,7 @@ import { CacheProvider } from 'memoose-js';
6
6
  import { TaskQueuesManager } from './TaskQueuesManager';
7
7
  import { TaskStore } from './TaskStore';
8
8
  import { IAsyncTaskManager } from './async/async-task-manager';
9
+ import { ITaskLifecycleProvider, TaskHandlerLifecycleConfig } from './lifecycle.js';
9
10
  export interface AsyncTask<ID> {
10
11
  task: CronTask<ID>;
11
12
  promise: Promise<void>;
@@ -17,10 +18,18 @@ export declare class TaskRunner<ID> {
17
18
  private taskQueue;
18
19
  private taskStore;
19
20
  private generateId;
21
+ private lifecycleProvider?;
22
+ private lifecycleConfig?;
20
23
  private readonly logger;
21
24
  private lockManager;
22
- constructor(messageQueue: IMessageQueue<ID>, taskQueue: TaskQueuesManager<ID>, taskStore: TaskStore<ID>, cacheProvider: CacheProvider<any>, generateId: () => ID);
25
+ private readonly taskStartTimes;
26
+ constructor(messageQueue: IMessageQueue<ID>, taskQueue: TaskQueuesManager<ID>, taskStore: TaskStore<ID>, cacheProvider: CacheProvider<any>, generateId: () => ID, lifecycleProvider?: ITaskLifecycleProvider | undefined, lifecycleConfig?: TaskHandlerLifecycleConfig | undefined);
23
27
  run(taskRunnerId: string, tasksRaw: Array<CronTask<ID>>, asyncTaskManager?: IAsyncTaskManager, abortSignal?: AbortSignal): Promise<ActionResults<ID> & {
24
28
  asyncTasks: AsyncTask<ID>[];
25
29
  }>;
30
+ private emitLifecycleEvent;
31
+ private buildTaskContext;
32
+ private emitTaskStarted;
33
+ private emitTaskCompleted;
34
+ private emitTaskFailed;
26
35
  }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Task Queue Lifecycle Types
3
+ * Provides interfaces for task and worker lifecycle callbacks
4
+ */
5
+ export interface TaskContext {
6
+ /** Unique task identifier */
7
+ task_id: string;
8
+ /** Optional hash for deduplication */
9
+ task_hash?: string;
10
+ /** Task type identifier */
11
+ task_type: string;
12
+ /** Queue this task belongs to */
13
+ queue_id: string;
14
+ /** Task payload (empty if include_payload is false) */
15
+ payload: Record<string, unknown>;
16
+ /** Current retry attempt (1-based) */
17
+ attempt: number;
18
+ /** Maximum retries allowed */
19
+ max_retries: number;
20
+ /** When task was scheduled */
21
+ scheduled_at: Date;
22
+ /** Worker processing this task */
23
+ worker_id?: string;
24
+ }
25
+ export interface TaskTiming {
26
+ /** Time spent waiting in queue (ms) */
27
+ queued_duration_ms: number;
28
+ /** Time spent executing (ms) */
29
+ processing_duration_ms: number;
30
+ /** End-to-end duration (ms) */
31
+ total_duration_ms: number;
32
+ }
33
+ export interface ITaskLifecycleProvider {
34
+ /** Called when a task is added to the queue */
35
+ onTaskScheduled?(ctx: TaskContext): void | Promise<void>;
36
+ /** Called when a worker picks up a task for processing */
37
+ onTaskStarted?(ctx: TaskContext & {
38
+ started_at: Date;
39
+ queued_duration_ms: number;
40
+ }): void | Promise<void>;
41
+ /** Called when a task completes successfully */
42
+ onTaskCompleted?(ctx: TaskContext & {
43
+ timing: TaskTiming;
44
+ result?: unknown;
45
+ }): void | Promise<void>;
46
+ /** Called when a task fails (before retry decision) */
47
+ onTaskFailed?(ctx: TaskContext & {
48
+ timing: TaskTiming;
49
+ error: Error;
50
+ will_retry: boolean;
51
+ next_attempt_at?: Date;
52
+ }): void | Promise<void>;
53
+ /** Called when a task exhausts all retries */
54
+ onTaskExhausted?(ctx: TaskContext & {
55
+ timing: TaskTiming;
56
+ error: Error;
57
+ total_attempts: number;
58
+ }): void | Promise<void>;
59
+ /** Called when a task is manually cancelled/discarded */
60
+ onTaskCancelled?(ctx: TaskContext & {
61
+ reason: string;
62
+ }): void | Promise<void>;
63
+ }
64
+ export interface WorkerInfo {
65
+ /** Unique worker identifier */
66
+ worker_id: string;
67
+ /** Hostname of the machine */
68
+ hostname: string;
69
+ /** Process ID */
70
+ pid: number;
71
+ /** When worker started */
72
+ started_at: Date;
73
+ /** Queues this worker is consuming */
74
+ enabled_queues: string[];
75
+ }
76
+ export interface WorkerStats {
77
+ /** Total tasks processed */
78
+ tasks_processed: number;
79
+ /** Successfully completed tasks */
80
+ tasks_succeeded: number;
81
+ /** Failed tasks */
82
+ tasks_failed: number;
83
+ /** Average processing time (ms) */
84
+ avg_processing_ms: number;
85
+ /** Currently processing task info */
86
+ current_task?: {
87
+ task_type: string;
88
+ started_at: Date;
89
+ };
90
+ }
91
+ export interface IWorkerLifecycleProvider {
92
+ /** Called when a worker starts consuming tasks */
93
+ onWorkerStarted?(info: WorkerInfo): void | Promise<void>;
94
+ /** Called periodically with worker stats */
95
+ onWorkerHeartbeat?(info: WorkerInfo & {
96
+ stats: WorkerStats;
97
+ memory_usage_mb: number;
98
+ cpu_percent?: number;
99
+ }): void | Promise<void>;
100
+ /** Called when a worker stops */
101
+ onWorkerStopped?(info: WorkerInfo & {
102
+ reason: 'shutdown' | 'error' | 'idle_timeout';
103
+ final_stats: WorkerStats;
104
+ }): void | Promise<void>;
105
+ /** Called when worker starts processing a batch */
106
+ onBatchStarted?(info: WorkerInfo & {
107
+ batch_size: number;
108
+ task_types: string[];
109
+ }): void | Promise<void>;
110
+ /** Called when worker finishes processing a batch */
111
+ onBatchCompleted?(info: WorkerInfo & {
112
+ batch_size: number;
113
+ succeeded: number;
114
+ failed: number;
115
+ duration_ms: number;
116
+ }): void | Promise<void>;
117
+ }
118
+ export interface TaskHandlerLifecycleConfig {
119
+ /** Callback execution mode: 'sync' blocks, 'async' is fire-and-forget */
120
+ mode?: 'sync' | 'async';
121
+ /** Heartbeat interval in ms (default: 5000) */
122
+ heartbeat_interval_ms?: number;
123
+ /** Include payload in task context (default: false for performance) */
124
+ include_payload?: boolean;
125
+ }
126
+ export interface TaskHandlerConfig {
127
+ /** Task lifecycle event provider */
128
+ lifecycleProvider?: ITaskLifecycleProvider;
129
+ /** Worker lifecycle event provider */
130
+ workerProvider?: IWorkerLifecycleProvider;
131
+ /** Lifecycle callback configuration */
132
+ lifecycle?: TaskHandlerLifecycleConfig;
133
+ }