소스 검색

refactor: avoid passing on singleton-like object instances of ModuleManager and LogBook

Kristian Vos 2 년 전
부모
커밋
01c2835942

+ 7 - 5
backend/src/BaseModule.ts

@@ -1,4 +1,4 @@
-import { Log } from "./LogBook";
+import LogBook, { Log } from "./LogBook";
 import ModuleManager from "./ModuleManager";
 import { ModuleStatus } from "./types/Modules";
 
@@ -7,6 +7,8 @@ import { ModuleStatus } from "./types/Modules";
 export default abstract class BaseModule {
 	protected moduleManager: ModuleManager;
 
+	protected logBook: LogBook;
+
 	protected name: string;
 
 	protected status: ModuleStatus;
@@ -14,11 +16,11 @@ export default abstract class BaseModule {
 	/**
 	 * Base Module
 	 *
-	 * @param moduleManager - Module manager class
 	 * @param name - Module name
 	 */
-	public constructor(moduleManager: ModuleManager, name: string) {
-		this.moduleManager = moduleManager;
+	public constructor(name: string) {
+		this.moduleManager = ModuleManager.getPrimaryInstance();
+		this.logBook = LogBook.getPrimaryInstance();
 		this.name = name;
 		this.status = "LOADED";
 		this.log(`Module (${this.name}) loaded`);
@@ -97,7 +99,7 @@ export default abstract class BaseModule {
 		} = {
 			...(typeof log === "string" ? { message: log } : log)
 		};
-		this.moduleManager.logBook.log({
+		this.logBook.log({
 			message,
 			type,
 			category: `modules.${this.getName()}`,

+ 2 - 13
backend/src/Job.ts

@@ -1,7 +1,5 @@
 import BaseModule from "./BaseModule";
 import JobQueue from "./JobQueue";
-import LogBook from "./LogBook";
-import ModuleManager from "./ModuleManager";
 import { JobOptions } from "./types/JobOptions";
 import { JobStatus } from "./types/JobStatus";
 import { Jobs, Module, Modules } from "./types/Modules";
@@ -34,10 +32,6 @@ export default class Job {
 
 	protected startedAt: number;
 
-	protected moduleManager: ModuleManager;
-
-	protected logBook: LogBook;
-
 	protected jobQueue: JobQueue;
 
 	/**
@@ -52,19 +46,14 @@ export default class Job {
 		name: string,
 		module: Module,
 		callback: (job: Job, resolve: () => void, reject: () => void) => void,
-		options: { priority: number; longJob?: string },
-		moduleManager: ModuleManager,
-		logBook: LogBook
+		options: { priority: number; longJob?: string }
 	) {
 		this.name = name;
 		this.module = module;
 		this.callback = callback;
 		this.priority = 1;
 
-		this.moduleManager = moduleManager;
-		this.logBook = logBook;
-
-		this.jobQueue = new JobQueue(moduleManager, logBook);
+		this.jobQueue = new JobQueue();
 
 		if (options) {
 			const { priority, longJob } = options;

+ 4 - 8
backend/src/JobContext.ts

@@ -13,13 +13,9 @@ export default class JobContext {
 
 	protected job: Job;
 
-	public constructor(
-		moduleManager: ModuleManager,
-		logBook: LogBook,
-		job: Job
-	) {
-		this.moduleManager = moduleManager;
-		this.logBook = logBook;
+	public constructor(job: Job) {
+		this.moduleManager = ModuleManager.getPrimaryInstance();
+		this.logBook = LogBook.getPrimaryInstance();
 		this.job = job;
 	}
 
@@ -36,7 +32,7 @@ export default class JobContext {
 		} = {
 			...(typeof log === "string" ? { message: log } : log)
 		};
-		this.moduleManager.logBook.log({
+		this.logBook.log({
 			message,
 			type,
 			category: `${this.job.getModule().getName()}.${this.job.getName()}`,

+ 6 - 11
backend/src/JobQueue.ts

@@ -38,7 +38,7 @@ export default class JobQueue {
 	/**
 	 * Job Queue
 	 */
-	public constructor(moduleManager: ModuleManager, logBook: LogBook) {
+	public constructor(moduleManager: ModuleManager | null = null) {
 		this.concurrency = 1;
 		this.isPaused = true;
 		this.jobs = [];
@@ -46,8 +46,9 @@ export default class JobQueue {
 		this.active = [];
 		this.stats = {};
 		this.processLock = false;
-		this.moduleManager = moduleManager;
-		this.logBook = logBook;
+		this.moduleManager =
+			moduleManager ?? ModuleManager.getPrimaryInstance();
+		this.logBook = LogBook.getPrimaryInstance();
 	}
 
 	/**
@@ -146,11 +147,7 @@ export default class JobQueue {
 						jobName.toString(),
 						module,
 						(job, resolveJob, rejectJob) => {
-							const jobContext = new JobContext(
-								this.moduleManager,
-								this.logBook,
-								job
-							);
+							const jobContext = new JobContext(job);
 							jobFunction
 								.apply(module, [jobContext, payload])
 								.then((response: ReturnType) => {
@@ -182,9 +179,7 @@ export default class JobQueue {
 						},
 						{
 							priority: (options && options.priority) || 10
-						},
-						this.moduleManager,
-						this.logBook
+						}
 					);
 
 					const runDirectly = !!(options && options.runDirectly);

+ 10 - 0
backend/src/LogBook.ts

@@ -32,6 +32,8 @@ const COLOR_CYAN = "\x1b[36m";
 const COLOR_RESET = "\x1b[0m";
 
 export default class LogBook {
+	static primaryInstance: LogBook;
+
 	// A list of log objects stored in memory, if enabled generally
 	private logs: Log[];
 
@@ -299,4 +301,12 @@ export default class LogBook {
 			}
 		}
 	}
+
+	static getPrimaryInstance(): LogBook {
+		return this.primaryInstance;
+	}
+
+	static setPrimaryInstance(logBook: LogBook) {
+		this.primaryInstance = logBook;
+	}
 }

+ 13 - 9
backend/src/ModuleManager.ts

@@ -2,25 +2,21 @@ import BaseModule from "./BaseModule";
 import Job from "./Job";
 import JobContext from "./JobContext";
 import JobQueue from "./JobQueue";
-import LogBook from "./LogBook";
 import { JobOptions } from "./types/JobOptions";
 import { Jobs, Modules, ModuleStatus, ModuleClass } from "./types/Modules";
 
 export default class ModuleManager {
-	private modules?: Modules;
+	static primaryInstance: ModuleManager;
 
-	public logBook: LogBook;
+	private modules?: Modules;
 
 	private jobQueue: JobQueue;
 
 	/**
 	 * Module Manager
-	 *
-	 * @param logBook - Logbook
 	 */
-	public constructor(logBook: LogBook) {
-		this.logBook = logBook;
-		this.jobQueue = new JobQueue(this, logBook);
+	public constructor() {
+		this.jobQueue = new JobQueue(this);
 	}
 
 	/**
@@ -101,7 +97,7 @@ export default class ModuleManager {
 		};
 		const { default: Module }: { default: ModuleClass<Modules[T]> } =
 			await import(`./modules/${mapper[moduleName]}`);
-		return new Module(this);
+		return new Module();
 	}
 
 	/**
@@ -184,4 +180,12 @@ export default class ModuleManager {
 	): Promise<ReturnType> {
 		return this.jobQueue.runJob(moduleName, jobName, payload, options);
 	}
+
+	static getPrimaryInstance(): ModuleManager {
+		return this.primaryInstance;
+	}
+
+	static setPrimaryInstance(moduleManager: ModuleManager) {
+		this.primaryInstance = moduleManager;
+	}
 }

+ 3 - 1
backend/src/main.ts

@@ -5,6 +5,7 @@ import LogBook from "./LogBook";
 import Job from "./Job";
 
 const logBook = new LogBook();
+LogBook.setPrimaryInstance(logBook);
 
 process.removeAllListeners("uncaughtException");
 process.on("uncaughtException", err => {
@@ -26,7 +27,8 @@ process.on("uncaughtException", err => {
 	});
 });
 
-const moduleManager = new ModuleManager(logBook);
+const moduleManager = new ModuleManager();
+ModuleManager.setPrimaryInstance(moduleManager);
 moduleManager.startup();
 
 // TOOD remove, or put behind debug option

+ 5 - 3
backend/src/modules/DataModule.spec.ts

@@ -18,9 +18,11 @@ describe("Data Module", function () {
 	const moduleManager = Object.getPrototypeOf(
 		sinon.createStubInstance(ModuleManager)
 	);
-	moduleManager.logBook = sinon.createStubInstance(LogBook);
+	ModuleManager.setPrimaryInstance(moduleManager);
+	const logBook = sinon.createStubInstance(LogBook);
+	LogBook.setPrimaryInstance(logBook);
 	moduleManager.jobQueue = sinon.createStubInstance(JobQueue);
-	const dataModule = new DataModule(moduleManager);
+	const dataModule = new DataModule();
 	const jobContext = sinon.createStubInstance(JobContext);
 	const testData = { abc: [] };
 
@@ -63,7 +65,7 @@ describe("Data Module", function () {
 	});
 
 	it("module loaded and started", function () {
-		moduleManager.logBook.log.should.have.been.called;
+		logBook.log.should.have.been.called;
 		dataModule.getName().should.equal("data");
 		dataModule.getStatus().should.equal("STARTED");
 	});

+ 2 - 5
backend/src/modules/DataModule.ts

@@ -4,7 +4,6 @@ import { createHash } from "node:crypto";
 import { createClient, RedisClientType } from "redis";
 import JobContext from "../JobContext";
 import BaseModule from "../BaseModule";
-import ModuleManager from "../ModuleManager";
 import Schema, { Types } from "../Schema";
 import { Collections } from "../types/Collections";
 import { Document as SchemaDocument } from "../types/Document";
@@ -55,11 +54,9 @@ export default class DataModule extends BaseModule {
 
 	/**
 	 * Data Module
-	 *
-	 * @param moduleManager - Module manager class
 	 */
-	public constructor(moduleManager: ModuleManager) {
-		super(moduleManager, "data");
+	public constructor() {
+		super("data");
 	}
 
 	/**

+ 3 - 6
backend/src/modules/StationModule.ts

@@ -1,16 +1,13 @@
 import JobContext from "../JobContext";
 import { UniqueMethods } from "../types/Modules";
 import BaseModule from "../BaseModule";
-import ModuleManager from "../ModuleManager";
 
 export default class StationModule extends BaseModule {
 	/**
 	 * Station Module
-	 *
-	 * @param moduleManager - Module manager class
 	 */
-	public constructor(moduleManager: ModuleManager) {
-		super(moduleManager, "stations");
+	public constructor() {
+		super("stations");
 	}
 
 	/**
@@ -51,7 +48,7 @@ export default class StationModule extends BaseModule {
 
 	public async addC(context: JobContext) {
 		context.log("ADDC");
-		await new Promise(() => {});
+		// await new Promise(() => {});
 	}
 }
 

+ 1 - 2
backend/src/types/Modules.ts

@@ -1,12 +1,11 @@
 import DataModule, { DataModuleJobs } from "../modules/DataModule";
 import StationModule, { StationModuleJobs } from "../modules/StationModule";
-import ModuleManager from "../ModuleManager";
 import BaseModule from "../BaseModule";
 
 export type Module = BaseModule;
 
 export type ModuleClass<Module extends typeof BaseModule> = {
-	new (moduleManager: ModuleManager): Module;
+	new (): Module;
 };
 
 export type Jobs = {