ModuleManager.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import BaseModule from "./BaseModule";
  2. import Job from "./Job";
  3. import JobContext from "./JobContext";
  4. import JobQueue from "./JobQueue";
  5. import { JobOptions } from "./types/JobOptions";
  6. import { Jobs, Modules, ModuleStatus, ModuleClass } from "./types/Modules";
  7. export default class ModuleManager {
  8. static primaryInstance: ModuleManager;
  9. private modules?: Modules;
  10. private jobQueue: JobQueue;
  11. /**
  12. * Module Manager
  13. */
  14. public constructor() {
  15. this.jobQueue = new JobQueue(this);
  16. }
  17. /**
  18. * getStatus - Get status of modules
  19. *
  20. * @returns Module statuses
  21. */
  22. public getStatus() {
  23. const status: Record<string, ModuleStatus> = {};
  24. Object.entries(this.modules || {}).forEach(([name, module]) => {
  25. status[name] = module.getStatus();
  26. });
  27. return status;
  28. }
  29. /**
  30. * getJobsStats - Get statistics of job queue
  31. *
  32. * @returns Job queue statistics
  33. */
  34. public getJobsStats() {
  35. return this.jobQueue.getStats();
  36. }
  37. /**
  38. * getJobsStatus - Get status of job queue
  39. *
  40. * @returns Job queue status
  41. */
  42. public getJobsStatus() {
  43. return this.jobQueue.getStatus();
  44. }
  45. /**
  46. * getQueueStatus - Get status of queued jobs
  47. *
  48. * @returns Job statuses
  49. */
  50. public getQueueStatus() {
  51. return this.jobQueue.getQueueStatus();
  52. }
  53. /**
  54. * Gets a job from the queue by jobId
  55. *
  56. * @returns Job
  57. */
  58. public getJob(jobId: string, recursive = false) {
  59. return this.jobQueue.getJob(jobId, recursive);
  60. }
  61. /**
  62. * Gets a list of all jobs running directly in the ModuleManager job queue
  63. */
  64. public getJobs() {
  65. return this.jobQueue.getJobs();
  66. }
  67. /**
  68. * Gets a module
  69. *
  70. */
  71. public getModule(moduleName: keyof Modules) {
  72. return this.modules && this.modules[moduleName];
  73. }
  74. /**
  75. * loadModule - Load and initialize module
  76. *
  77. * @param moduleName - Name of the module
  78. * @returns Module
  79. */
  80. private async loadModule<T extends keyof Modules>(moduleName: T) {
  81. const mapper = {
  82. data: "DataModule",
  83. // events: "EventsModule",
  84. stations: "StationModule"
  85. };
  86. const { default: Module }: { default: ModuleClass<Modules[T]> } =
  87. await import(`./modules/${mapper[moduleName]}`);
  88. return new Module();
  89. }
  90. /**
  91. * loadModules - Load and initialize all modules
  92. *
  93. * @returns Promise
  94. */
  95. private async loadModules() {
  96. this.modules = {
  97. data: await this.loadModule("data"),
  98. // events: await this.loadModule("events"),
  99. stations: await this.loadModule("stations")
  100. };
  101. }
  102. /**
  103. * startup - Handle startup
  104. */
  105. public async startup() {
  106. await this.loadModules().catch(async err => {
  107. await this.shutdown();
  108. throw err;
  109. });
  110. if (!this.modules) throw new Error("No modules were loaded");
  111. await Promise.all(
  112. Object.values(this.modules).map(async module => {
  113. await module.startup().catch(async err => {
  114. module.setStatus("ERROR");
  115. throw err;
  116. });
  117. })
  118. ).catch(async err => {
  119. await this.shutdown();
  120. throw err;
  121. });
  122. this.jobQueue.resume();
  123. }
  124. /**
  125. * shutdown - Handle shutdown
  126. */
  127. public async shutdown() {
  128. if (this.modules)
  129. await Promise.all(
  130. Object.values(this.modules).map(async module => {
  131. if (
  132. module.getStatus() === "STARTED" ||
  133. module.getStatus() === "STARTING" ||
  134. module.getStatus() === "ERROR"
  135. )
  136. await module.shutdown();
  137. })
  138. );
  139. }
  140. /**
  141. * runJob - Run a job
  142. *
  143. * @param moduleName - Module name
  144. * @param jobName - Job name
  145. * @param params - Params
  146. */
  147. public runJob<
  148. ModuleNameType extends keyof Jobs & keyof Modules,
  149. JobNameType extends keyof Jobs[ModuleNameType] &
  150. keyof Omit<Modules[ModuleNameType], keyof BaseModule>,
  151. PayloadType extends "payload" extends keyof Jobs[ModuleNameType][JobNameType]
  152. ? Jobs[ModuleNameType][JobNameType]["payload"] extends undefined
  153. ? Record<string, never>
  154. : Jobs[ModuleNameType][JobNameType]["payload"]
  155. : Record<string, never>,
  156. ReturnType = "returns" extends keyof Jobs[ModuleNameType][JobNameType]
  157. ? Jobs[ModuleNameType][JobNameType]["returns"]
  158. : never
  159. >(
  160. moduleName: ModuleNameType,
  161. jobName: JobNameType,
  162. payload: PayloadType,
  163. options?: JobOptions
  164. ): Promise<ReturnType> {
  165. return this.jobQueue.runJob(moduleName, jobName, payload, options);
  166. }
  167. static getPrimaryInstance(): ModuleManager {
  168. return this.primaryInstance;
  169. }
  170. static setPrimaryInstance(moduleManager: ModuleManager) {
  171. this.primaryInstance = moduleManager;
  172. }
  173. }