@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
package/dist/index.cjs CHANGED
@@ -1,6 +1,51 @@
1
1
  "use strict";
2
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
3
+ var __typeError = (msg) => {
4
+ throw TypeError(msg);
5
+ };
6
+ var __using = (stack, value, async) => {
7
+ if (value != null) {
8
+ if (typeof value !== "object" && typeof value !== "function") __typeError("Object expected");
9
+ var dispose, inner;
10
+ if (async) dispose = value[__knownSymbol("asyncDispose")];
11
+ if (dispose === void 0) {
12
+ dispose = value[__knownSymbol("dispose")];
13
+ if (async) inner = dispose;
14
+ }
15
+ if (typeof dispose !== "function") __typeError("Object not disposable");
16
+ if (inner) dispose = function() {
17
+ try {
18
+ inner.call(this);
19
+ } catch (e) {
20
+ return Promise.reject(e);
21
+ }
22
+ };
23
+ stack.push([async, dispose, value]);
24
+ } else if (async) {
25
+ stack.push([async]);
26
+ }
27
+ return value;
28
+ };
29
+ var __callDispose = (stack, error, hasError) => {
30
+ var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
31
+ return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
32
+ };
33
+ var fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e);
34
+ var next = (it) => {
35
+ while (it = stack.pop()) {
36
+ try {
37
+ var result = it[1] && it[1].call(it[2]);
38
+ if (it[0]) return Promise.resolve(result).then(next, (e) => (fail(e), next()));
39
+ } catch (e) {
40
+ fail(e);
41
+ }
42
+ }
43
+ if (hasError) throw error;
44
+ };
45
+ return next();
46
+ };
2
47
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const PrismaAdapter = require("./PrismaAdapter-D-Bjaonm.cjs");
48
+ const PrismaAdapter = require("./PrismaAdapter-CT8dxOZX.cjs");
4
49
  const mq = require("@supergrowthai/mq");
5
50
  const client = require("./client-DgdG7pT6.cjs");
6
51
  const utils_taskIdGen = require("./utils/task-id-gen.cjs");
@@ -555,144 +600,326 @@ function requireChunk() {
555
600
  }
556
601
  var chunkExports = requireChunk();
557
602
  const chunk = /* @__PURE__ */ getDefaultExportFromCjs(chunkExports);
603
+ class DisposableLockBatch {
604
+ constructor(lockManager, onError) {
605
+ this.lockManager = lockManager;
606
+ this.onError = onError;
607
+ this.lockIds = [];
608
+ this.disposed = false;
609
+ }
610
+ /**
611
+ * Get the list of currently held lock IDs
612
+ */
613
+ get heldLocks() {
614
+ return this.lockIds;
615
+ }
616
+ /**
617
+ * Number of locks currently held
618
+ */
619
+ get size() {
620
+ return this.lockIds.length;
621
+ }
622
+ /**
623
+ * Acquire a lock and track it for automatic release
624
+ */
625
+ async acquire(lockId, timeout) {
626
+ if (this.disposed) {
627
+ throw new Error("Cannot acquire lock on disposed DisposableLockBatch");
628
+ }
629
+ const acquired = await this.lockManager.acquire(lockId, timeout);
630
+ if (acquired) {
631
+ this.lockIds.push(lockId);
632
+ }
633
+ return acquired;
634
+ }
635
+ /**
636
+ * AsyncDisposable implementation - releases all locks
637
+ */
638
+ async [Symbol.asyncDispose]() {
639
+ if (this.disposed) return;
640
+ this.disposed = true;
641
+ await Promise.all(
642
+ this.lockIds.map(
643
+ (lockId) => this.lockManager.release(lockId).catch((err) => {
644
+ if (this.onError) {
645
+ this.onError(lockId, err);
646
+ }
647
+ })
648
+ )
649
+ );
650
+ }
651
+ }
558
652
  class TaskRunner {
559
- constructor(messageQueue, taskQueue, taskStore, cacheProvider, generateId) {
653
+ constructor(messageQueue, taskQueue, taskStore, cacheProvider, generateId, lifecycleProvider, lifecycleConfig) {
560
654
  this.messageQueue = messageQueue;
561
655
  this.taskQueue = taskQueue;
562
656
  this.taskStore = taskStore;
563
657
  this.generateId = generateId;
658
+ this.lifecycleProvider = lifecycleProvider;
659
+ this.lifecycleConfig = lifecycleConfig;
660
+ this.taskStartTimes = /* @__PURE__ */ new Map();
564
661
  this.logger = new client.Logger("TaskRunner", client.LogLevel.INFO);
565
662
  this.lockManager = new LockManager(cacheProvider, {
566
663
  prefix: "task_lock_",
567
664
  defaultTimeout: 30 * 60
568
665
  });
569
666
  }
667
+ // ============ Lifecycle Helpers ============
570
668
  async run(taskRunnerId, tasksRaw, asyncTaskManager, abortSignal) {
571
- this.logger.info(`[${taskRunnerId}] Starting task runner`);
572
- this.logger.info(`[${taskRunnerId}] Processing ${tasksRaw.length} provided tasks`);
573
- if (abortSignal?.aborted) {
574
- this.logger.info(`[${taskRunnerId}] AbortSignal already aborted, returning empty results`);
575
- return { successTasks: [], failedTasks: [], newTasks: [], ignoredTasks: [], asyncTasks: [] };
576
- }
577
- const tasks = await this.lockManager.filterLocked(tasksRaw, utils_taskIdGen.tId);
578
- this.logger.info(`[${taskRunnerId}] Found ${tasks.length} not locked tasks to process`);
579
- await Promise.all(tasks.map((t) => this.lockManager.acquire(utils_taskIdGen.tId(t))));
580
- const groupedTasksObject = tasks.reduce((acc, task) => {
581
- acc[task.type] = acc[task.type] || [];
582
- acc[task.type].push(task);
583
- return acc;
584
- }, {});
585
- const groupedTasksArray = Object.keys(groupedTasksObject).reduce((acc, type) => {
586
- acc.push({ type, tasks: groupedTasksObject[type] });
587
- return acc;
588
- }, []);
589
- this.logger.info(`[${taskRunnerId}] Task groups: ${groupedTasksArray.map((g) => `${g.type}: ${g.tasks.length}`).join(", ")}`);
590
- const actions = new core_Actions.Actions(taskRunnerId);
591
- const asyncTasks = [];
592
- const processedTaskIds = /* @__PURE__ */ new Set();
593
- for (let i = 0; i < groupedTasksArray.length; i++) {
669
+ var _stack = [];
670
+ try {
671
+ this.logger.info(`[${taskRunnerId}] Starting task runner`);
672
+ this.logger.info(`[${taskRunnerId}] Processing ${tasksRaw.length} provided tasks`);
594
673
  if (abortSignal?.aborted) {
595
- this.logger.info(`[${taskRunnerId}] AbortSignal detected, stopping task group processing`);
596
- break;
674
+ this.logger.info(`[${taskRunnerId}] AbortSignal already aborted, returning empty results`);
675
+ return { successTasks: [], failedTasks: [], newTasks: [], ignoredTasks: [], asyncTasks: [] };
597
676
  }
598
- const taskGroup = groupedTasksArray[i];
599
- const firstTask = taskGroup.tasks[0];
600
- if (!firstTask) {
601
- this.logger.warn(`[${taskRunnerId}] No tasks found for type: ${taskGroup.type}`);
602
- continue;
677
+ const tasks = await this.lockManager.filterLocked(tasksRaw, utils_taskIdGen.tId);
678
+ this.logger.info(`[${taskRunnerId}] Found ${tasks.length} not locked tasks to process`);
679
+ const locks = __using(_stack, new DisposableLockBatch(
680
+ this.lockManager,
681
+ (lockId, err) => this.logger.error(`[${taskRunnerId}] Failed to release lock ${lockId}:`, err)
682
+ ), true);
683
+ for (const task of tasks) {
684
+ await locks.acquire(utils_taskIdGen.tId(task));
603
685
  }
604
- const executor = this.taskQueue.getExecutor(firstTask.queue_id, taskGroup.type);
605
- if (!executor) {
606
- this.logger.warn(`[${taskRunnerId}] No executor found for type: ${taskGroup.type} in queue ${firstTask.queue_id}`);
607
- for (const task of taskGroup.tasks) {
608
- const taskWithId = task.id ? task : { ...task, id: this.generateId() };
609
- actions.addIgnoredTask(taskWithId);
686
+ const groupedTasksObject = tasks.reduce((acc, task) => {
687
+ acc[task.type] = acc[task.type] || [];
688
+ acc[task.type].push(task);
689
+ return acc;
690
+ }, {});
691
+ const groupedTasksArray = Object.keys(groupedTasksObject).reduce((acc, type) => {
692
+ acc.push({ type, tasks: groupedTasksObject[type] });
693
+ return acc;
694
+ }, []);
695
+ this.logger.info(`[${taskRunnerId}] Task groups: ${groupedTasksArray.map((g) => `${g.type}: ${g.tasks.length}`).join(", ")}`);
696
+ const actions = new core_Actions.Actions(taskRunnerId);
697
+ const asyncTasks = [];
698
+ const processedTaskIds = /* @__PURE__ */ new Set();
699
+ for (let i = 0; i < groupedTasksArray.length; i++) {
700
+ if (abortSignal?.aborted) {
701
+ this.logger.info(`[${taskRunnerId}] AbortSignal detected, stopping task group processing`);
702
+ break;
610
703
  }
611
- continue;
612
- }
613
- if (executor.asyncConfig?.handoffTimeout && asyncTaskManager && !asyncTaskManager.canAcceptTask()) {
614
- this.logger.warn(`[${taskRunnerId}] Async queue full, rescheduling ${taskGroup.tasks.length} ${taskGroup.type} tasks for 3 min later`);
615
- const rescheduledTasks = taskGroup.tasks.map((task) => ({
616
- ...task,
617
- execute_at: new Date(Date.now() + 18e4),
618
- status: "scheduled"
619
- }));
620
- await this.taskStore.updateTasksForRetry(rescheduledTasks);
621
- continue;
622
- }
623
- taskGroup.tasks.forEach((task) => processedTaskIds.add(utils_taskIdGen.tId(task)));
624
- this.logger.info(`[${taskRunnerId}] Processing ${taskGroup.tasks.length} tasks of type: ${taskGroup.type}`);
625
- if (executor.multiple) {
626
- await executor.onTasks(taskGroup.tasks, actions).catch((err) => this.logger.error(`[${taskRunnerId}] executor.onTasks failed: ${err}`));
627
- } else {
628
- if (executor.parallel) {
629
- const chunks = chunk(taskGroup.tasks, executor.chunkSize);
630
- this.logger.info(`[${taskRunnerId}] Processing in parallel chunks of ${executor.chunkSize}`);
631
- for (const chunk2 of chunks) {
632
- const chunkTasks = [];
633
- for (let j = 0; j < chunk2.length; j++) {
634
- const taskActions = actions.forkForTask(chunk2[j]);
635
- chunkTasks.push(executor.onTask(chunk2[j], taskActions).catch((err) => this.logger.error(`[${taskRunnerId}] executor.onTask failed: ${err}`)));
636
- }
637
- await Promise.all(chunkTasks);
704
+ const taskGroup = groupedTasksArray[i];
705
+ const firstTask = taskGroup.tasks[0];
706
+ if (!firstTask) {
707
+ this.logger.warn(`[${taskRunnerId}] No tasks found for type: ${taskGroup.type}`);
708
+ continue;
709
+ }
710
+ const executor = this.taskQueue.getExecutor(firstTask.queue_id, taskGroup.type);
711
+ if (!executor) {
712
+ this.logger.warn(`[${taskRunnerId}] No executor found for type: ${taskGroup.type} in queue ${firstTask.queue_id}`);
713
+ for (const task of taskGroup.tasks) {
714
+ const taskWithId = task.id ? task : { ...task, id: this.generateId() };
715
+ actions.addIgnoredTask(taskWithId);
638
716
  }
717
+ continue;
718
+ }
719
+ if (executor.asyncConfig?.handoffTimeout && asyncTaskManager && !asyncTaskManager.canAcceptTask()) {
720
+ this.logger.warn(`[${taskRunnerId}] Async queue full, rescheduling ${taskGroup.tasks.length} ${taskGroup.type} tasks for 3 min later`);
721
+ const rescheduledTasks = taskGroup.tasks.map((task) => ({
722
+ ...task,
723
+ execute_at: new Date(Date.now() + 18e4),
724
+ status: "scheduled"
725
+ }));
726
+ await this.taskStore.updateTasksForRetry(rescheduledTasks);
727
+ continue;
728
+ }
729
+ taskGroup.tasks.forEach((task) => processedTaskIds.add(utils_taskIdGen.tId(task)));
730
+ this.logger.info(`[${taskRunnerId}] Processing ${taskGroup.tasks.length} tasks of type: ${taskGroup.type}`);
731
+ if (executor.multiple) {
732
+ await executor.onTasks(taskGroup.tasks, actions).catch((err) => this.logger.error(`[${taskRunnerId}] executor.onTasks failed: ${err}`));
639
733
  } else {
640
- const timeoutMs = executor.asyncConfig?.handoffTimeout;
641
- for (let j = 0; j < taskGroup.tasks.length; j++) {
642
- const task = taskGroup.tasks[j];
643
- if (!timeoutMs) {
644
- const taskActions = actions.forkForTask(task);
645
- await executor.onTask(task, taskActions).catch((err) => this.logger.error(`[${taskRunnerId}] executor.onTask failed: ${err}`));
646
- } else {
647
- const startTime = Date.now();
648
- const taskActions = actions.forkForTask(task);
649
- const taskPromise = executor.onTask(task, taskActions).catch((err) => {
650
- this.logger.error(`[${taskRunnerId}] executor.onTask failed: ${err}`);
651
- });
652
- let timeoutId;
653
- const timeoutPromise = new Promise((resolve) => {
654
- timeoutId = setTimeout(() => {
655
- resolve("~~~timeout");
656
- }, timeoutMs);
657
- });
658
- const result = await Promise.race([taskPromise, timeoutPromise]);
659
- if (timeoutId) {
660
- clearTimeout(timeoutId);
734
+ if (executor.parallel) {
735
+ const chunks = chunk(taskGroup.tasks, executor.chunkSize);
736
+ this.logger.info(`[${taskRunnerId}] Processing in parallel chunks of ${executor.chunkSize}`);
737
+ for (const taskChunk of chunks) {
738
+ for (const task of taskChunk) {
739
+ this.emitTaskStarted(task, taskRunnerId);
661
740
  }
662
- if (result === "~~~timeout") {
663
- this.logger.info(`[${taskRunnerId}] Task ${utils_taskIdGen.tId(task)} (${task.type}) exceeded ${timeoutMs}ms, marking for async handoff`);
664
- if (!asyncTaskManager) {
665
- throw new Error(`Task ${task.type} exceeded timeout but AsyncTaskManager not initialized!`);
741
+ const chunkPromises = [];
742
+ for (let j = 0; j < taskChunk.length; j++) {
743
+ const taskActions = actions.forkForTask(taskChunk[j]);
744
+ chunkPromises.push(executor.onTask(taskChunk[j], taskActions).catch((err) => this.logger.error(`[${taskRunnerId}] executor.onTask failed: ${err}`)));
745
+ }
746
+ await Promise.all(chunkPromises);
747
+ for (const task of taskChunk) {
748
+ const resultStatus = actions.getTaskResultStatus(utils_taskIdGen.tId(task));
749
+ if (resultStatus === "success") {
750
+ this.emitTaskCompleted(task, taskRunnerId);
751
+ } else if (resultStatus === "fail") {
752
+ const retryCount = task.execution_stats?.retry_count || 0;
753
+ const maxRetries = task.retries ?? executor.default_retries ?? 0;
754
+ const willRetry = retryCount < maxRetries;
755
+ this.emitTaskFailed(task, taskRunnerId, new Error("Task failed"), willRetry);
756
+ }
757
+ }
758
+ }
759
+ } else {
760
+ const timeoutMs = executor.asyncConfig?.handoffTimeout;
761
+ for (let j = 0; j < taskGroup.tasks.length; j++) {
762
+ const task = taskGroup.tasks[j];
763
+ if (!timeoutMs) {
764
+ this.emitTaskStarted(task, taskRunnerId);
765
+ const taskActions = actions.forkForTask(task);
766
+ await executor.onTask(task, taskActions).catch((err) => this.logger.error(`[${taskRunnerId}] executor.onTask failed: ${err}`));
767
+ const resultStatus = actions.getTaskResultStatus(utils_taskIdGen.tId(task));
768
+ if (resultStatus === "success") {
769
+ this.emitTaskCompleted(task, taskRunnerId);
770
+ } else if (resultStatus === "fail") {
771
+ const retryCount = task.execution_stats?.retry_count || 0;
772
+ const maxRetries = task.retries ?? executor.default_retries ?? 0;
773
+ const willRetry = retryCount < maxRetries;
774
+ this.emitTaskFailed(task, taskRunnerId, new Error("Task failed"), willRetry);
666
775
  }
667
- if (!task.id) {
668
- this.logger.error(`[${taskRunnerId}] Cannot hand off task without id (type: ${task.type}). Task will continue but won't be tracked.`);
669
- } else {
670
- const asyncActions = new core_async_AsyncActions.AsyncActions(this.messageQueue, this.taskStore, this.taskQueue, actions, task, this.generateId);
671
- const asyncPromise = taskPromise.finally(async () => {
672
- try {
673
- await asyncActions.onPromiseFulfilled();
674
- } catch (err) {
675
- this.logger.error(`[${taskRunnerId}] Failed to execute async actions for task ${utils_taskIdGen.tId(task)}:`, err);
676
- }
677
- });
678
- asyncTasks.push({
679
- task,
680
- promise: asyncPromise,
681
- startTime,
682
- actions: asyncActions
683
- });
776
+ } else {
777
+ this.emitTaskStarted(task, taskRunnerId);
778
+ const startTime = Date.now();
779
+ const taskActions = actions.forkForTask(task);
780
+ const taskPromise = executor.onTask(task, taskActions).catch((err) => {
781
+ this.logger.error(`[${taskRunnerId}] executor.onTask failed: ${err}`);
782
+ });
783
+ let timeoutId;
784
+ const timeoutPromise = new Promise((resolve) => {
785
+ timeoutId = setTimeout(() => {
786
+ resolve("~~~timeout");
787
+ }, timeoutMs);
788
+ });
789
+ const result = await Promise.race([taskPromise, timeoutPromise]);
790
+ if (timeoutId) {
791
+ clearTimeout(timeoutId);
792
+ }
793
+ if (result !== "~~~timeout") {
794
+ const resultStatus = actions.getTaskResultStatus(utils_taskIdGen.tId(task));
795
+ if (resultStatus === "success") {
796
+ this.emitTaskCompleted(task, taskRunnerId);
797
+ } else if (resultStatus === "fail") {
798
+ const retryCount = task.execution_stats?.retry_count || 0;
799
+ const maxRetries = task.retries ?? executor.default_retries ?? 0;
800
+ const willRetry = retryCount < maxRetries;
801
+ this.emitTaskFailed(task, taskRunnerId, new Error("Task failed"), willRetry);
802
+ }
803
+ }
804
+ if (result === "~~~timeout") {
805
+ this.logger.info(`[${taskRunnerId}] Task ${utils_taskIdGen.tId(task)} (${task.type}) exceeded ${timeoutMs}ms, marking for async handoff`);
806
+ if (!asyncTaskManager) {
807
+ throw new Error(`Task ${task.type} exceeded timeout but AsyncTaskManager not initialized!`);
808
+ }
809
+ if (!task.id) {
810
+ this.logger.error(`[${taskRunnerId}] Cannot hand off task without id (type: ${task.type}). Task will continue but won't be tracked.`);
811
+ } else {
812
+ const asyncActions = new core_async_AsyncActions.AsyncActions(this.messageQueue, this.taskStore, this.taskQueue, actions, task, this.generateId);
813
+ const asyncPromise = taskPromise.finally(async () => {
814
+ try {
815
+ await asyncActions.onPromiseFulfilled();
816
+ } catch (err) {
817
+ this.logger.error(`[${taskRunnerId}] Failed to execute async actions for task ${utils_taskIdGen.tId(task)}:`, err);
818
+ }
819
+ });
820
+ asyncTasks.push({
821
+ task,
822
+ promise: asyncPromise,
823
+ startTime,
824
+ actions: asyncActions
825
+ });
826
+ }
684
827
  }
685
828
  }
686
829
  }
687
830
  }
688
831
  }
689
832
  }
833
+ const asyncTaskIds = asyncTasks.map((at) => utils_taskIdGen.tId(at.task));
834
+ const results = actions.extractSyncResults(asyncTaskIds);
835
+ this.logger.info(`[${taskRunnerId}] Completing run - Success: ${results.successTasks.length}, Failed: ${results.failedTasks.length}, New: ${results.newTasks.length}, Async: ${asyncTasks.length}, Ignored: ${results.ignoredTasks.length}`);
836
+ return { ...results, asyncTasks };
837
+ } catch (_) {
838
+ var _error = _, _hasError = true;
839
+ } finally {
840
+ var _promise = __callDispose(_stack, _error, _hasError);
841
+ _promise && await _promise;
842
+ }
843
+ }
844
+ emitLifecycleEvent(callback, ctx) {
845
+ if (!callback) return;
846
+ try {
847
+ const result = callback(ctx);
848
+ if (result instanceof Promise) {
849
+ result.catch((err) => {
850
+ this.logger.error(`[TQ] Lifecycle callback error: ${err}`);
851
+ });
852
+ }
853
+ } catch (err) {
854
+ this.logger.error(`[TQ] Lifecycle callback error: ${err}`);
855
+ }
856
+ }
857
+ buildTaskContext(task, workerId) {
858
+ const retryCount = task.execution_stats && typeof task.execution_stats.retry_count === "number" ? task.execution_stats.retry_count : 0;
859
+ const executor = this.taskQueue.getExecutor(task.queue_id, task.type);
860
+ const maxRetries = task.retries ?? executor?.default_retries ?? 0;
861
+ const payload = task.payload;
862
+ return {
863
+ task_id: task.id?.toString() || utils_taskIdGen.tId(task),
864
+ task_hash: payload?.task_hash,
865
+ task_type: task.type,
866
+ queue_id: task.queue_id,
867
+ payload: this.lifecycleConfig?.include_payload ? payload : {},
868
+ attempt: retryCount + 1,
869
+ max_retries: maxRetries,
870
+ scheduled_at: task.created_at || /* @__PURE__ */ new Date(),
871
+ worker_id: workerId
872
+ };
873
+ }
874
+ emitTaskStarted(task, workerId) {
875
+ const startedAt = Date.now();
876
+ this.taskStartTimes.set(utils_taskIdGen.tId(task), startedAt);
877
+ if (this.lifecycleProvider?.onTaskStarted) {
878
+ const ctx = this.buildTaskContext(task, workerId);
879
+ const queuedDuration = startedAt - (task.created_at?.getTime() || startedAt);
880
+ this.emitLifecycleEvent(
881
+ this.lifecycleProvider.onTaskStarted,
882
+ {
883
+ ...ctx,
884
+ started_at: new Date(startedAt),
885
+ queued_duration_ms: queuedDuration
886
+ }
887
+ );
888
+ }
889
+ }
890
+ emitTaskCompleted(task, workerId, result) {
891
+ const completedAt = Date.now();
892
+ const startedAt = this.taskStartTimes.get(utils_taskIdGen.tId(task)) || completedAt;
893
+ this.taskStartTimes.delete(utils_taskIdGen.tId(task));
894
+ if (this.lifecycleProvider?.onTaskCompleted) {
895
+ const ctx = this.buildTaskContext(task, workerId);
896
+ const timing = {
897
+ queued_duration_ms: startedAt - (task.created_at?.getTime() || startedAt),
898
+ processing_duration_ms: completedAt - startedAt,
899
+ total_duration_ms: completedAt - (task.created_at?.getTime() || completedAt)
900
+ };
901
+ this.emitLifecycleEvent(
902
+ this.lifecycleProvider.onTaskCompleted,
903
+ { ...ctx, timing, result }
904
+ );
905
+ }
906
+ }
907
+ emitTaskFailed(task, workerId, error, willRetry, nextAttemptAt) {
908
+ const completedAt = Date.now();
909
+ const startedAt = this.taskStartTimes.get(utils_taskIdGen.tId(task)) || completedAt;
910
+ this.taskStartTimes.delete(utils_taskIdGen.tId(task));
911
+ if (this.lifecycleProvider?.onTaskFailed) {
912
+ const ctx = this.buildTaskContext(task, workerId);
913
+ const timing = {
914
+ queued_duration_ms: startedAt - (task.created_at?.getTime() || startedAt),
915
+ processing_duration_ms: completedAt - startedAt,
916
+ total_duration_ms: completedAt - (task.created_at?.getTime() || completedAt)
917
+ };
918
+ this.emitLifecycleEvent(
919
+ this.lifecycleProvider.onTaskFailed,
920
+ { ...ctx, timing, error, will_retry: willRetry, next_attempt_at: nextAttemptAt }
921
+ );
690
922
  }
691
- const asyncTaskIds = asyncTasks.map((at) => utils_taskIdGen.tId(at.task));
692
- const results = actions.extractSyncResults(asyncTaskIds);
693
- this.logger.info(`[${taskRunnerId}] Completing run - Success: ${results.successTasks.length}, Failed: ${results.failedTasks.length}, New: ${results.newTasks.length}, Async: ${asyncTasks.length}, Ignored: ${results.ignoredTasks.length}`);
694
- await Promise.all(tasks.filter((t) => processedTaskIds.has(utils_taskIdGen.tId(t))).map((t) => this.lockManager.release(utils_taskIdGen.tId(t))));
695
- return { ...results, asyncTasks };
696
923
  }
697
924
  }
698
925
  function getEnabledQueues() {
@@ -706,7 +933,7 @@ const STATS_THRESHOLD = parseInt(process.env.TQ_STATS_THRESHOLD || "1000");
706
933
  const FAILURE_THRESHOLD = parseInt(process.env.TQ_STATS_FAILURE_THRESHOLD || "100");
707
934
  const INSTANCE_ID = process.env.INSTANCE_ID || "unknown";
708
935
  class TaskHandler {
709
- constructor(messageQueue, taskQueuesManager, databaseAdapter, cacheAdapter, asyncTaskManager, notificationProvider) {
936
+ constructor(messageQueue, taskQueuesManager, databaseAdapter, cacheAdapter, asyncTaskManager, notificationProvider, config) {
710
937
  this.messageQueue = messageQueue;
711
938
  this.taskQueuesManager = taskQueuesManager;
712
939
  this.databaseAdapter = databaseAdapter;
@@ -714,10 +941,39 @@ class TaskHandler {
714
941
  this.asyncTaskManager = asyncTaskManager;
715
942
  this.notificationProvider = notificationProvider;
716
943
  this.matureTaskTimer = null;
944
+ this.heartbeatTimer = null;
945
+ this.enabledQueues = [];
946
+ this.workerStarted = false;
947
+ this.workerStats = {
948
+ tasks_processed: 0,
949
+ tasks_succeeded: 0,
950
+ tasks_failed: 0,
951
+ avg_processing_ms: 0,
952
+ current_task: void 0
953
+ };
954
+ this.totalProcessingMs = 0;
717
955
  this.queueStats = /* @__PURE__ */ new Map();
718
956
  this.logger = new client.Logger("TaskHandler", client.LogLevel.INFO);
957
+ this.config = config || {};
958
+ this.workerId = `${(void 0)()}-${process.pid}-${Date.now()}`;
959
+ this.workerStartedAt = /* @__PURE__ */ new Date();
719
960
  this.taskStore = new TaskStore(databaseAdapter);
720
- this.taskRunner = new TaskRunner(messageQueue, taskQueuesManager, this.taskStore, this.cacheAdapter, databaseAdapter.generateId.bind(databaseAdapter));
961
+ this.taskRunner = new TaskRunner(
962
+ messageQueue,
963
+ taskQueuesManager,
964
+ this.taskStore,
965
+ this.cacheAdapter,
966
+ databaseAdapter.generateId.bind(databaseAdapter),
967
+ this.config.lifecycleProvider,
968
+ this.config.lifecycle
969
+ );
970
+ }
971
+ // ============ Lifecycle Event Helpers ============
972
+ get lifecycleProvider() {
973
+ return this.config.lifecycleProvider;
974
+ }
975
+ get workerProvider() {
976
+ return this.config.workerProvider;
721
977
  }
722
978
  async addTasks(tasks) {
723
979
  const diffedItems = tasks.reduce(
@@ -743,24 +999,40 @@ class TaskHandler {
743
999
  const iQueues = Object.keys(diffedItems.immediate);
744
1000
  for (let i = 0; i < iQueues.length; i++) {
745
1001
  const queue = iQueues[i];
746
- const tasks2 = diffedItems.immediate[queue].map((task) => {
1002
+ const queueTasks = diffedItems.immediate[queue].map((task) => {
747
1003
  const executor = this.taskQueuesManager.getExecutor(task.queue_id, task.type);
748
1004
  const shouldStoreOnFailure = executor?.store_on_failure ?? false;
749
1005
  const id = shouldStoreOnFailure ? { id: this.databaseAdapter.generateId() } : {};
750
1006
  return { ...id, ...task };
751
1007
  });
752
- await this.messageQueue.addMessages(queue, tasks2);
1008
+ await this.messageQueue.addMessages(queue, queueTasks);
1009
+ if (this.lifecycleProvider?.onTaskScheduled) {
1010
+ for (const task of queueTasks) {
1011
+ this.emitLifecycleEvent(
1012
+ this.lifecycleProvider.onTaskScheduled,
1013
+ this.buildTaskContext(task)
1014
+ );
1015
+ }
1016
+ }
753
1017
  }
754
1018
  const fQueues = Object.keys(diffedItems.future);
755
1019
  for (let i = 0; i < fQueues.length; i++) {
756
1020
  const queue = fQueues[i];
757
- const tasks2 = diffedItems.future[queue].map((task) => {
1021
+ const queueTasks = diffedItems.future[queue].map((task) => {
758
1022
  const executor = this.taskQueuesManager.getExecutor(task.queue_id, task.type);
759
1023
  const shouldStoreOnFailure = executor?.store_on_failure ?? false;
760
1024
  const id = shouldStoreOnFailure ? { id: this.databaseAdapter.generateId() } : {};
761
1025
  return { ...id, ...task };
762
1026
  });
763
- await this.taskStore.addTasksToScheduled(tasks2);
1027
+ await this.taskStore.addTasksToScheduled(queueTasks);
1028
+ if (this.lifecycleProvider?.onTaskScheduled) {
1029
+ for (const task of queueTasks) {
1030
+ this.emitLifecycleEvent(
1031
+ this.lifecycleProvider.onTaskScheduled,
1032
+ this.buildTaskContext(task)
1033
+ );
1034
+ }
1035
+ }
764
1036
  }
765
1037
  }
766
1038
  async postProcessTasks({
@@ -771,10 +1043,12 @@ class TaskHandler {
771
1043
  const tasksToRetry = [];
772
1044
  const finalFailedTasks = [];
773
1045
  let discardedTasksCount = 0;
1046
+ const MAX_RETRY_DELAY_MS = 5 * 60 * 1e3;
774
1047
  for (const task of failedTasksRaw) {
775
1048
  const taskRetryCount = task.execution_stats && typeof task.execution_stats.retry_count === "number" ? task.execution_stats.retry_count : 0;
776
1049
  const taskRetryAfter = task.retry_after || 2e3;
777
- const retryAfter = taskRetryAfter * Math.pow(taskRetryCount + 1, 2);
1050
+ const calculatedDelay = taskRetryAfter * Math.pow(taskRetryCount + 1, 2);
1051
+ const retryAfter = Math.min(calculatedDelay, MAX_RETRY_DELAY_MS);
778
1052
  const executeAt = Date.now() + retryAfter;
779
1053
  const maxRetries = this.getRetryCount(task);
780
1054
  if (task.id && taskRetryCount < maxRetries) {
@@ -816,6 +1090,23 @@ class TaskHandler {
816
1090
  } else {
817
1091
  discardedTasksCount++;
818
1092
  this.logger.info(`Discarding task of type ${task.type} after ${taskRetryCount} retries`);
1093
+ if (this.lifecycleProvider?.onTaskExhausted) {
1094
+ const ctx = this.buildTaskContext(task);
1095
+ const errorMessage = task.execution_stats?.last_error || "Task exhausted all retries";
1096
+ this.emitLifecycleEvent(
1097
+ this.lifecycleProvider.onTaskExhausted,
1098
+ {
1099
+ ...ctx,
1100
+ timing: {
1101
+ queued_duration_ms: 0,
1102
+ processing_duration_ms: 0,
1103
+ total_duration_ms: Date.now() - (task.created_at?.getTime() || Date.now())
1104
+ },
1105
+ error: new Error(errorMessage),
1106
+ total_attempts: taskRetryCount + 1
1107
+ }
1108
+ );
1109
+ }
819
1110
  }
820
1111
  }
821
1112
  if (discardedTasksCount > 0) {
@@ -840,6 +1131,18 @@ class TaskHandler {
840
1131
  this.logger.info(`AbortSignal detected, skipping processing of ${tasks.length} tasks for stream ${streamName}`);
841
1132
  return { failedTasks: [], newTasks: [], successTasks: [], asyncTasks: [], ignoredTasks: [] };
842
1133
  }
1134
+ const batchStartTime = Date.now();
1135
+ const taskTypes = [...new Set(tasks.map((t) => t.type))];
1136
+ if (this.workerProvider?.onBatchStarted) {
1137
+ this.emitLifecycleEvent(
1138
+ this.workerProvider.onBatchStarted,
1139
+ {
1140
+ ...this.buildWorkerInfo(),
1141
+ batch_size: tasks.length,
1142
+ task_types: taskTypes
1143
+ }
1144
+ );
1145
+ }
843
1146
  this.logger.debug(`Processing ${tasks.length} tasks for stream ${streamName}`);
844
1147
  const {
845
1148
  failedTasks,
@@ -890,10 +1193,118 @@ class TaskHandler {
890
1193
  stats.async += asyncTasks.length;
891
1194
  stats.ignored += ignoredTasks.length;
892
1195
  await this.reportQueueStats(streamName);
1196
+ const batchDuration = Date.now() - batchStartTime;
1197
+ this.updateWorkerStats(successTasks.length, failedTasks.length, batchDuration);
1198
+ if (this.workerProvider?.onBatchCompleted) {
1199
+ this.emitLifecycleEvent(
1200
+ this.workerProvider.onBatchCompleted,
1201
+ {
1202
+ ...this.buildWorkerInfo(),
1203
+ batch_size: tasks.length,
1204
+ succeeded: successTasks.length,
1205
+ failed: failedTasks.length,
1206
+ duration_ms: batchDuration
1207
+ }
1208
+ );
1209
+ }
893
1210
  this.logger.debug(`Completed processing for stream ${streamName}: ${successTasks.length} succeeded, ${failedTasks.length} failed, ${newTasks.length} new tasks, ${ignoredTasks.length} ignored`);
894
1211
  return { failedTasks, newTasks, successTasks, asyncTasks, ignoredTasks };
895
1212
  }, abortSignal);
896
1213
  }
1214
+ taskProcessServer(abortSignal) {
1215
+ const queues = getEnabledQueues();
1216
+ this.enabledQueues = queues;
1217
+ if (!this.workerStarted) {
1218
+ this.workerStarted = true;
1219
+ this.emitWorkerStarted();
1220
+ this.startHeartbeat();
1221
+ }
1222
+ for (let i = 0; i < queues.length; i++) {
1223
+ this.logger.info(`Starting consumer for queue: ${queues[i]}`);
1224
+ this.startConsumingTasks(queues[i], abortSignal);
1225
+ }
1226
+ this.logger.info("Starting mature tasks processor");
1227
+ this.processMatureTasks(abortSignal);
1228
+ abortSignal?.addEventListener("abort", () => {
1229
+ this.stopHeartbeat();
1230
+ this.emitWorkerStopped("shutdown");
1231
+ });
1232
+ }
1233
+ buildWorkerInfo() {
1234
+ return {
1235
+ worker_id: this.workerId,
1236
+ hostname: (void 0)(),
1237
+ pid: process.pid,
1238
+ started_at: this.workerStartedAt,
1239
+ enabled_queues: this.enabledQueues
1240
+ };
1241
+ }
1242
+ emitWorkerStarted() {
1243
+ if (!this.workerProvider?.onWorkerStarted) return;
1244
+ this.emitLifecycleEvent(this.workerProvider.onWorkerStarted, this.buildWorkerInfo());
1245
+ }
1246
+ emitWorkerStopped(reason) {
1247
+ if (!this.workerProvider?.onWorkerStopped) return;
1248
+ this.emitLifecycleEvent(
1249
+ this.workerProvider.onWorkerStopped,
1250
+ {
1251
+ ...this.buildWorkerInfo(),
1252
+ reason,
1253
+ final_stats: { ...this.workerStats }
1254
+ }
1255
+ );
1256
+ }
1257
+ emitWorkerHeartbeat() {
1258
+ if (!this.workerProvider?.onWorkerHeartbeat) return;
1259
+ const memUsage = process.memoryUsage();
1260
+ this.emitLifecycleEvent(
1261
+ this.workerProvider.onWorkerHeartbeat,
1262
+ {
1263
+ ...this.buildWorkerInfo(),
1264
+ stats: { ...this.workerStats },
1265
+ memory_usage_mb: memUsage.heapUsed / 1024 / 1024
1266
+ }
1267
+ );
1268
+ }
1269
+ startHeartbeat() {
1270
+ if (this.heartbeatTimer) return;
1271
+ const intervalMs = this.config.lifecycle?.heartbeat_interval_ms || 5e3;
1272
+ this.heartbeatTimer = setInterval(() => {
1273
+ this.emitWorkerHeartbeat();
1274
+ }, intervalMs);
1275
+ }
1276
+ stopHeartbeat() {
1277
+ if (this.heartbeatTimer) {
1278
+ clearInterval(this.heartbeatTimer);
1279
+ this.heartbeatTimer = null;
1280
+ }
1281
+ }
1282
+ updateWorkerStats(succeeded, failed, processingMs) {
1283
+ this.workerStats.tasks_processed += succeeded + failed;
1284
+ this.workerStats.tasks_succeeded += succeeded;
1285
+ this.workerStats.tasks_failed += failed;
1286
+ this.totalProcessingMs += processingMs;
1287
+ if (this.workerStats.tasks_processed > 0) {
1288
+ this.workerStats.avg_processing_ms = this.totalProcessingMs / this.workerStats.tasks_processed;
1289
+ }
1290
+ }
1291
+ emitLifecycleEvent(callback, ctx) {
1292
+ if (!callback) return;
1293
+ try {
1294
+ const result = callback(ctx);
1295
+ if (this.config.lifecycle?.mode === "sync" && result instanceof Promise) {
1296
+ result.catch((err) => {
1297
+ this.logger.error(`[TQ] Lifecycle callback error: ${err}`);
1298
+ });
1299
+ } else if (result instanceof Promise) {
1300
+ result.catch((err) => {
1301
+ this.logger.error(`[TQ] Lifecycle callback error: ${err}`);
1302
+ });
1303
+ }
1304
+ } catch (err) {
1305
+ this.logger.error(`[TQ] Lifecycle callback error: ${err}`);
1306
+ }
1307
+ }
897
1308
  processMatureTasks(abortSignal) {
898
1309
  if (this.matureTaskTimer) clearInterval(this.matureTaskTimer);
899
1310
  if (abortSignal?.aborted) {
@@ -937,14 +1348,20 @@ class TaskHandler {
937
1348
  });
938
1349
  });
939
1350
  }
940
- taskProcessServer(abortSignal) {
941
- const queues = getEnabledQueues();
942
- for (let i = 0; i < queues.length; i++) {
943
- this.logger.info(`Starting consumer for queue: ${queues[i]}`);
944
- this.startConsumingTasks(queues[i], abortSignal);
945
- }
946
- this.logger.info("Starting mature tasks processor");
947
- this.processMatureTasks(abortSignal);
1351
+ buildTaskContext(task) {
1352
+ const maxRetries = this.getRetryCount(task);
1353
+ const retryCount = task.execution_stats && typeof task.execution_stats.retry_count === "number" ? task.execution_stats.retry_count : 0;
1354
+ const payload = task.payload;
1355
+ return {
1356
+ task_id: task.id?.toString() || "",
1357
+ task_hash: payload?.task_hash,
1358
+ task_type: task.type,
1359
+ queue_id: task.queue_id,
1360
+ payload: this.config.lifecycle?.include_payload ? payload : {},
1361
+ attempt: retryCount + 1,
1362
+ max_retries: maxRetries,
1363
+ scheduled_at: task.created_at || /* @__PURE__ */ new Date()
1364
+ };
948
1365
  }
949
1366
  processBatch(queueId, processor, limit, abortSignal) {
950
1367
  if (abortSignal?.aborted) {
@@ -1056,6 +1473,7 @@ class TaskHandler {
1056
1473
  }
1057
1474
  }
1058
1475
  }
1476
+ const logger = new client.Logger("TaskQueuesManager", client.LogLevel.INFO);
1059
1477
  class TaskQueuesManager {
1060
1478
  constructor(messageQueue) {
1061
1479
  this.messageQueue = messageQueue;
@@ -1075,7 +1493,7 @@ class TaskQueuesManager {
1075
1493
  }
1076
1494
  const queueMap = this.queueTaskExecutorMap.get(queueName);
1077
1495
  queueMap.set(taskType, executor);
1078
- console.log(`Registered task executor for ${taskType} on queue ${queueName}`);
1496
+ logger.info(`Registered task executor for ${taskType} on queue ${queueName}`);
1079
1497
  }
1080
1498
  /**
1081
1499
  * Gets the task executor for a specific queue and task type
@@ -1112,6 +1530,62 @@ class TaskQueuesManager {
1112
1530
  return Array.from(queueMap.keys());
1113
1531
  }
1114
1532
  }
1533
+ class ConsoleHealthProvider {
1534
+ constructor(prefix = "[Health]") {
1535
+ this.prefix = prefix;
1536
+ }
1537
+ // ============ Task Lifecycle ============
1538
+ onTaskScheduled(ctx) {
1539
+ console.log(`${this.prefix} Task scheduled: ${ctx.task_type} (${ctx.task_id}) in queue ${ctx.queue_id}`);
1540
+ }
1541
+ onTaskStarted(ctx) {
1542
+ console.log(`${this.prefix} Task started: ${ctx.task_type} (${ctx.task_id}) - queued for ${ctx.queued_duration_ms}ms`);
1543
+ }
1544
+ onTaskCompleted(ctx) {
1545
+ console.log(
1546
+ `${this.prefix} Task completed: ${ctx.task_type} (${ctx.task_id}) - processing: ${ctx.timing.processing_duration_ms}ms, total: ${ctx.timing.total_duration_ms}ms`
1547
+ );
1548
+ }
1549
+ onTaskFailed(ctx) {
1550
+ console.log(
1551
+ `${this.prefix} Task failed: ${ctx.task_type} (${ctx.task_id}) - error: ${ctx.error.message}, will_retry: ${ctx.will_retry}`
1552
+ );
1553
+ }
1554
+ onTaskExhausted(ctx) {
1555
+ console.log(
1556
+ `${this.prefix} Task exhausted: ${ctx.task_type} (${ctx.task_id}) - total attempts: ${ctx.total_attempts}, error: ${ctx.error.message}`
1557
+ );
1558
+ }
1559
+ onTaskCancelled(ctx) {
1560
+ console.log(`${this.prefix} Task cancelled: ${ctx.task_type} (${ctx.task_id}) - reason: ${ctx.reason}`);
1561
+ }
1562
+ // ============ Worker Lifecycle ============
1563
+ onWorkerStarted(info) {
1564
+ console.log(
1565
+ `${this.prefix} Worker started: ${info.worker_id} on ${info.hostname} (PID: ${info.pid}) - queues: [${info.enabled_queues.join(", ")}]`
1566
+ );
1567
+ }
1568
+ onWorkerHeartbeat(info) {
1569
+ console.log(
1570
+ `${this.prefix} Worker heartbeat: ${info.worker_id} - processed: ${info.stats.tasks_processed}, success: ${info.stats.tasks_succeeded}, failed: ${info.stats.tasks_failed}, avg: ${info.stats.avg_processing_ms.toFixed(2)}ms, memory: ${info.memory_usage_mb.toFixed(2)}MB`
1571
+ );
1572
+ }
1573
+ onWorkerStopped(info) {
1574
+ console.log(
1575
+ `${this.prefix} Worker stopped: ${info.worker_id} - reason: ${info.reason} - final stats: ${info.final_stats.tasks_processed} processed, ${info.final_stats.tasks_succeeded} succeeded, ${info.final_stats.tasks_failed} failed`
1576
+ );
1577
+ }
1578
+ onBatchStarted(info) {
1579
+ console.log(
1580
+ `${this.prefix} Batch started: ${info.batch_size} tasks - types: [${info.task_types.join(", ")}]`
1581
+ );
1582
+ }
1583
+ onBatchCompleted(info) {
1584
+ console.log(
1585
+ `${this.prefix} Batch completed: ${info.batch_size} tasks in ${info.duration_ms}ms - succeeded: ${info.succeeded}, failed: ${info.failed}`
1586
+ );
1587
+ }
1588
+ }
1115
1589
  exports.InMemoryAdapter = PrismaAdapter.InMemoryAdapter;
1116
1590
  exports.MongoDbAdapter = PrismaAdapter.MongoDbAdapter;
1117
1591
  exports.PrismaAdapter = PrismaAdapter.PrismaAdapter;
@@ -1119,6 +1593,7 @@ exports.tId = utils_taskIdGen.tId;
1119
1593
  exports.Actions = core_Actions.Actions;
1120
1594
  exports.AsyncActions = core_async_AsyncActions.AsyncActions;
1121
1595
  exports.AsyncTaskManager = core_async_AsyncTaskManager.AsyncTaskManager;
1596
+ exports.ConsoleHealthProvider = ConsoleHealthProvider;
1122
1597
  exports.TaskHandler = TaskHandler;
1123
1598
  exports.TaskQueuesManager = TaskQueuesManager;
1124
1599
  exports.TaskRunner = TaskRunner;