Просмотр исходного кода

refactor: Starting reworking job, queue and module structure

Owen Diffey 2 лет назад
Родитель
Сommit
658cfd0e64

+ 0 - 2
backend/src/BaseModule.ts

@@ -2,8 +2,6 @@ import LogBook, { Log } from "./LogBook";
 import ModuleManager from "./ModuleManager";
 import { ModuleStatus } from "./types/Modules";
 
-// type ModuleName = keyof Modules;
-
 export default abstract class BaseModule {
 	protected moduleManager: ModuleManager;
 

+ 92 - 72
backend/src/Job.ts

@@ -1,20 +1,22 @@
 import BaseModule from "./BaseModule";
-import JobQueue from "./JobQueue";
-import LogBook from "./LogBook";
+import JobContext from "./JobContext";
+import JobStatistics from "./JobStatistics";
+import LogBook, { Log } from "./LogBook";
+import ModuleManager from "./ModuleManager";
 import { JobOptions } from "./types/JobOptions";
 import { JobStatus } from "./types/JobStatus";
-import { Jobs, Module, Modules } from "./types/Modules";
+import { Modules } from "./types/Modules";
 
 export default class Job {
 	protected name: string;
 
-	protected module: Module;
+	protected module: Modules[keyof Modules];
 
-	protected callback: (
-		job: this,
-		resolve: () => void,
-		reject: () => void
-	) => void;
+	protected jobFunction: any;
+
+	protected payload: any;
+
+	protected context: JobContext;
 
 	protected priority: number;
 
@@ -33,10 +35,10 @@ export default class Job {
 
 	protected startedAt: number;
 
-	protected jobQueue: JobQueue;
-
 	protected logBook: LogBook;
 
+	protected jobStatistics: JobStatistics;
+
 	/**
 	 * Job
 	 *
@@ -47,18 +49,35 @@ export default class Job {
 	 */
 	public constructor(
 		name: string,
-		module: Module,
-		callback: (job: Job, resolve: () => void, reject: () => void) => void,
-		options: { priority: number; longJob?: string }
+		moduleName: keyof Modules,
+		payload: any,
+		options?: Omit<JobOptions, "runDirectly">
 	) {
 		this.name = name;
-		this.module = module;
-		this.callback = callback;
 		this.priority = 1;
 
-		this.jobQueue = new JobQueue();
+		const module = ModuleManager.getPrimaryInstance().getModule(moduleName);
+		if (!module) throw new Error("Module not found.");
+		this.module = module;
+
+		// eslint-disable-next-line
+		// @ts-ignore
+		const jobFunction = this.module[this.name];
+		if (!jobFunction || typeof jobFunction !== "function")
+			throw new Error("Job not found.");
+		if (Object.prototype.hasOwnProperty.call(BaseModule, this.name))
+			throw new Error("Illegal job function.");
+		this.jobFunction = jobFunction;
+
+		this.payload = payload;
+
+		this.context = new JobContext(this);
+
 		this.logBook = LogBook.getPrimaryInstance();
 
+		this.jobStatistics = JobStatistics.getPrimaryInstance();
+		this.jobStatistics.updateStats(this.getName(), "added");
+
 		if (options) {
 			const { priority, longJob } = options;
 			if (priority) this.priority = priority;
@@ -124,8 +143,6 @@ export default class Job {
 	 */
 	public setStatus(status: JobStatus) {
 		this.status = status;
-		if (this.status === "ACTIVE") this.jobQueue.resume();
-		else if (this.status === "PAUSED") this.jobQueue.pause();
 	}
 
 	/**
@@ -137,69 +154,72 @@ export default class Job {
 		return this.module;
 	}
 
-	/**
-	 * Gets the job queue for jobs running under this current job
-	 */
-	public getJobQueue() {
-		return this.jobQueue;
-	}
-
 	/**
 	 * execute - Execute job
 	 *
 	 * @returns Promise
 	 */
-	public execute(): Promise<void> {
-		return new Promise((resolve, reject) => {
-			this.setStatus("ACTIVE");
-			this.callback(this, resolve, reject);
-		});
+	public async execute() {
+		this.setStatus("ACTIVE");
+		return (
+			this.jobFunction
+				.apply(this.module, [this.context, this.payload])
+				// eslint-disable-next-line
+				// @ts-ignore
+				.then(response => {
+					this.log({
+						message: "Job completed successfully",
+						type: "success"
+					});
+					this.jobStatistics.updateStats(
+						this.getName(),
+						"successful"
+					);
+					return response;
+				})
+				.catch((err: any) => {
+					this.log({
+						message: `Job failed with error "${err}"`,
+						type: "error"
+					});
+					this.jobStatistics.updateStats(this.getName(), "failed");
+					throw err;
+				})
+				.finally(() => {
+					this.jobStatistics.updateStats(this.getName(), "total");
+					this.jobStatistics.updateStats(
+						this.getName(),
+						"averageTime",
+						Date.now() - this.startedAt
+					);
+					this.setStatus("COMPLETED");
+				})
+		);
 	}
 
 	/**
-	 * runJob - Run a job
+	 * Log a message in the context of the current job, which automatically sets the category and data
 	 *
-	 * @param moduleName - Module name
-	 * @param jobName - Job name
-	 * @param params - Params
+	 * @param log - Log message or object
 	 */
-	public runJob<
-		ModuleNameType extends keyof Jobs & keyof Modules,
-		JobNameType extends keyof Jobs[ModuleNameType] &
-			keyof Omit<Modules[ModuleNameType], keyof BaseModule>,
-		PayloadType extends "payload" extends keyof Jobs[ModuleNameType][JobNameType]
-			? Jobs[ModuleNameType][JobNameType]["payload"] extends undefined
-				? Record<string, never>
-				: Jobs[ModuleNameType][JobNameType]["payload"]
-			: Record<string, never>,
-		ReturnType = "returns" extends keyof Jobs[ModuleNameType][JobNameType]
-			? Jobs[ModuleNameType][JobNameType]["returns"]
-			: never
-	>(
-		moduleName: ModuleNameType,
-		jobName: JobNameType,
-		payload: PayloadType,
-		options?: JobOptions
-	): Promise<ReturnType> {
-		if (this.getStatus() !== "ACTIVE")
-			throw new Error(
-				`Cannot run a child job when the current job is not active. Current job: ${this.getName()}, attempted to run job: ${moduleName}.${jobName.toString()}.`
-			);
-
-		return new Promise<Awaited<Promise<ReturnType>>>((resolve, reject) => {
-			this.jobQueue
-				.runJob(moduleName, jobName, payload, options)
-				// @ts-ignore
-				.then(resolve)
-				.catch(reject)
-				.finally(() => {
-					if (this.getStatus() !== "ACTIVE")
-						this.logBook.log({
-							type: "error",
-							category: "jobs",
-							message: `Job ${this.getName()}(${this.getUuid()}) has had a child job (${moduleName}.${jobName.toString()}) complete, but the job was not active. This should never happen!`
-						});
-				});
+	public log(log: string | Omit<Log, "timestamp" | "category">) {
+		const {
+			message,
+			type = undefined,
+			data = {}
+		} = {
+			...(typeof log === "string" ? { message: log } : log)
+		};
+		this.logBook.log({
+			message,
+			type,
+			category: this.getName(),
+			data: {
+				moduleName: this.module.getName(),
+				jobName: this.name,
+				jobUuid: this.uuid,
+				...data
+			}
 		});
 	}
 }

+ 13 - 30
backend/src/JobContext.ts

@@ -1,22 +1,18 @@
-import { Jobs, Modules } from "./types/Modules";
-
-import Job from "./Job";
-import LogBook, { Log } from "./LogBook";
-import ModuleManager from "./ModuleManager";
 import BaseModule from "./BaseModule";
+import Job from "./Job";
+import JobQueue from "./JobQueue";
+import { Log } from "./LogBook";
 import { JobOptions } from "./types/JobOptions";
+import { Jobs, Modules } from "./types/Modules";
 
 export default class JobContext {
-	protected moduleManager: ModuleManager;
-
-	protected logBook: LogBook;
-
 	protected job: Job;
 
+	protected jobQueue: JobQueue;
+
 	public constructor(job: Job) {
-		this.moduleManager = ModuleManager.getPrimaryInstance();
-		this.logBook = LogBook.getPrimaryInstance();
 		this.job = job;
+		this.jobQueue = JobQueue.getPrimaryInstance();
 	}
 
 	/**
@@ -25,23 +21,7 @@ export default class JobContext {
 	 * @param log - Log message or object
 	 */
 	public log(log: string | Omit<Log, "timestamp" | "category">) {
-		const {
-			message,
-			type = undefined,
-			data = {}
-		} = {
-			...(typeof log === "string" ? { message: log } : log)
-		};
-		this.logBook.log({
-			message,
-			type,
-			category: `${this.job.getModule().getName()}.${this.job.getName()}`,
-			data: {
-				moduleName: this.job.getModule().getName(),
-				jobName: this.job.getName(),
-				...data
-			}
-		});
+		return this.job.log(log);
 	}
 
 	/**
@@ -51,7 +31,7 @@ export default class JobContext {
 	 * @param jobName - Job name
 	 * @param params - Params
 	 */
-	public runJob<
+	public async runJob<
 		ModuleNameType extends keyof Jobs & keyof Modules,
 		JobNameType extends keyof Jobs[ModuleNameType] &
 			keyof Omit<Modules[ModuleNameType], keyof BaseModule>,
@@ -69,6 +49,9 @@ export default class JobContext {
 		payload: PayloadType,
 		options?: JobOptions
 	): Promise<ReturnType> {
-		return this.job.runJob(moduleName, jobName, payload, options);
+		return this.jobQueue.runJob(moduleName, jobName, payload, {
+			runDirectly: true,
+			...(options ?? {})
+		});
 	}
 }

+ 52 - 143
backend/src/JobQueue.ts

@@ -1,14 +1,12 @@
 import BaseModule from "./BaseModule";
 import Job from "./Job";
-import JobContext from "./JobContext";
-import JobStatistics from "./JobStatistics";
-import LogBook from "./LogBook";
-import ModuleManager from "./ModuleManager";
 import { JobOptions } from "./types/JobOptions";
 import { JobStatus } from "./types/JobStatus";
 import { Jobs, Modules } from "./types/Modules";
 
 export default class JobQueue {
+	static primaryInstance = new this();
+
 	private concurrency: number;
 
 	private isPaused: boolean;
@@ -21,44 +19,25 @@ export default class JobQueue {
 
 	private processLock: boolean;
 
-	private moduleManager: ModuleManager;
-
-	private logBook: LogBook;
-
-	private jobStatistics: JobStatistics;
+	private callbacks: Record<
+		string,
+		{
+			resolve: (value: unknown) => void;
+			reject: (reason?: any) => void;
+		}
+	>;
 
 	/**
 	 * Job Queue
 	 */
-	public constructor(moduleManager: ModuleManager | null = null) {
-		this.concurrency = 1;
+	public constructor() {
+		this.concurrency = 10000;
 		this.isPaused = true;
 		this.jobs = [];
 		this.queue = [];
 		this.active = [];
+		this.callbacks = {};
 		this.processLock = false;
-		this.moduleManager =
-			moduleManager ?? ModuleManager.getPrimaryInstance();
-		this.logBook = LogBook.getPrimaryInstance();
-		this.jobStatistics = JobStatistics.getPrimaryInstance();
-	}
-
-	/**
-	 * add - Add job to queue
-	 *
-	 * @param job - Job
-	 */
-	public add(job: Job, runDirectly: boolean) {
-		this.jobStatistics.updateStats(job.getName(), "added");
-		this.jobs.push(job);
-		if (runDirectly) {
-			this.executeJob(job);
-		} else {
-			this.queue.push(job);
-			setTimeout(() => {
-				this.process();
-			}, 0);
-		}
 	}
 
 	/**
@@ -67,16 +46,8 @@ export default class JobQueue {
 	 * @param jobId - Job UUID
 	 * @returns Job if found
 	 */
-	public getJob(jobId: string, recursive = false) {
-		let job = this.jobs.find(job => job.getUuid() === jobId);
-		if (job || !recursive) return job;
-
-		this.jobs.some(currentJob => {
-			job = currentJob.getJobQueue().getJob(jobId, recursive);
-			return !!job;
-		});
-
-		return job;
+	public getJob(jobId: string) {
+		return this.jobs.find(job => job.getUuid() === jobId);
 	}
 
 	/**
@@ -103,7 +74,7 @@ export default class JobQueue {
 	 * @param jobName - Job name
 	 * @param params - Params
 	 */
-	public runJob<
+	public async runJob<
 		ModuleNameType extends keyof Jobs & keyof Modules,
 		JobNameType extends keyof Jobs[ModuleNameType] &
 			keyof Omit<Modules[ModuleNameType], keyof BaseModule>,
@@ -121,109 +92,27 @@ export default class JobQueue {
 		payload: PayloadType,
 		options?: JobOptions
 	): Promise<ReturnType> {
-		return new Promise((resolve, reject) => {
-			const module = this.moduleManager.getModule(
-				moduleName
-			) as Modules[ModuleNameType];
-			if (!module) reject(new Error("Module not found."));
-			else {
-				const jobFunction = module[jobName];
-				if (!jobFunction || typeof jobFunction !== "function")
-					reject(new Error("Job not found."));
-				else if (
-					Object.prototype.hasOwnProperty.call(BaseModule, jobName)
-				)
-					reject(new Error("Illegal job function."));
-				else {
-					const job = new Job(
-						jobName.toString(),
-						module,
-						(job, resolveJob, rejectJob) => {
-							const jobContext = new JobContext(job);
-							jobFunction
-								.apply(module, [jobContext, payload])
-								.then((response: ReturnType) => {
-									this.logBook.log({
-										message: "Job completed successfully",
-										type: "success",
-										category: "jobs",
-										data: {
-											jobName: job.getName(),
-											jobId: job.getUuid()
-										}
-									});
-									resolveJob();
-									resolve(response);
-								})
-								.catch((err: any) => {
-									this.logBook.log({
-										message: `Job failed with error "${err}"`,
-										type: "error",
-										category: "jobs",
-										data: {
-											jobName: job.getName(),
-											jobId: job.getUuid()
-										}
-									});
-									rejectJob();
-									reject(err);
-								});
-						},
-						{
-							priority: (options && options.priority) || 10
-						}
-					);
-
-					const runDirectly = !!(options && options.runDirectly);
-
-					this.add(job, runDirectly);
-				}
-			}
-		});
-	}
-
-	/**
-	 * Actually run a job function
-	 *
-	 * @param job - Initiated job
-	 */
-	public executeJob(job: Job) {
-		// Record when we started a job
-		const startTime = Date.now();
-		this.active.push(job);
-
-		job.execute()
-			.then(() => {
-				this.jobStatistics.updateStats(job.getName(), "successful");
-			})
-			.catch(() => {
-				this.jobStatistics.updateStats(job.getName(), "failed");
-			})
-			.finally(() => {
-				this.jobStatistics.updateStats(job.getName(), "total");
-				this.jobStatistics.updateStats(
-					job.getName(),
-					"averageTime",
-					Date.now() - startTime
-				);
+		const job = new Job(jobName.toString(), moduleName, payload, options);
 
-				job.setStatus("COMPLETED");
+		const runDirectly = !!(options && options.runDirectly);
 
-				// If the current job is in the active jobs array, remove it, and then run the process function to run another job
-				const activeJobIndex = this.active.indexOf(job);
-				if (activeJobIndex > -1) {
-					this.active.splice(activeJobIndex, 1);
-					setTimeout(() => {
-						this.process();
-					}, 0);
-				}
-			});
+		this.jobs.push(job);
+		if (runDirectly) {
+			return job.execute();
+		}
+		return new Promise((resolve, reject) => {
+			this.callbacks[job.getUuid()] = { resolve, reject };
+			this.queue.push(job);
+			this.process();
+		}).finally(() => {
+			delete this.callbacks[job.getUuid()];
+		}) as Promise<ReturnType>;
 	}
 
 	/**
 	 * process - Process queue
 	 */
-	private process() {
+	private async process() {
 		// If the process is locked, don't continue. This prevents running process at the same time which could lead to issues
 		if (this.processLock) return;
 		// If the queue is paused, we've reached the maximum number of active jobs, or there are no jobs in the queue, don't continue
@@ -254,10 +143,22 @@ export default class JobQueue {
 			this.queue.splice(this.queue.indexOf(job), 1);
 
 			// Execute the job
-			this.executeJob(job);
-
+			this.active.push(job);
+
+			const callback = this.callbacks[job.getUuid()];
+			job.execute()
+				.then(callback.resolve)
+				.catch(callback.reject)
+				.finally(() => {
+					// If the current job is in the active jobs array, remove it, and then run the process function to run another job
+					const activeJobIndex = this.active.indexOf(job);
+					if (activeJobIndex > -1) {
+						this.active.splice(activeJobIndex, 1);
+						this.process();
+					}
+				});
 			// Stop the for loop
-			break;
+			if (this.active.length >= this.concurrency) break;
 		}
 
 		// Unlock the process after the for loop is finished, so it can be run again
@@ -312,4 +213,12 @@ export default class JobQueue {
 	public getJobs() {
 		return this.jobs;
 	}
+
+	static getPrimaryInstance(): JobQueue {
+		return this.primaryInstance;
+	}
+
+	static setPrimaryInstance(instance: JobQueue) {
+		this.primaryInstance = instance;
+	}
 }

+ 3 - 3
backend/src/JobStatistics.ts

@@ -1,5 +1,5 @@
 export default class JobStatistics {
-	static primaryInstance: JobStatistics;
+	static primaryInstance = new this();
 
 	private stats: Record<
 		string,
@@ -74,7 +74,7 @@ export default class JobStatistics {
 		return this.primaryInstance;
 	}
 
-	static setPrimaryInstance(jobStatistics: JobStatistics) {
-		this.primaryInstance = jobStatistics;
+	static setPrimaryInstance(instance: JobStatistics) {
+		this.primaryInstance = instance;
 	}
 }

+ 12 - 12
backend/src/LogBook.ts

@@ -32,7 +32,7 @@ const COLOR_CYAN = "\x1b[36m";
 const COLOR_RESET = "\x1b[0m";
 
 export default class LogBook {
-	static primaryInstance: LogBook;
+	static primaryInstance = new this();
 
 	// A list of log objects stored in memory, if enabled generally
 	private logs: Log[];
@@ -57,15 +57,15 @@ export default class LogBook {
 				data: false,
 				color: true,
 				exclude: [
-					// // Success messages for jobs don't tend to be very helpful, so we exclude them by default
-					// {
-					// 	category: "jobs",
-					// 	type: "success"
-					// },
-					// // We don't want to show debug messages in the console by default
-					// {
-					// 	type: "debug"
-					// }
+					// Success messages for jobs don't tend to be very helpful, so we exclude them by default
+					{
+						category: "jobs",
+						type: "success"
+					},
+					// We don't want to show debug messages in the console by default
+					{
+						type: "debug"
+					}
 				]
 			},
 			memory: {
@@ -306,7 +306,7 @@ export default class LogBook {
 		return this.primaryInstance;
 	}
 
-	static setPrimaryInstance(logBook: LogBook) {
-		this.primaryInstance = logBook;
+	static setPrimaryInstance(instance: LogBook) {
+		this.primaryInstance = instance;
 	}
 }

+ 5 - 91
backend/src/ModuleManager.ts

@@ -1,26 +1,11 @@
-import BaseModule from "./BaseModule";
 import JobQueue from "./JobQueue";
-import JobStatistics from "./JobStatistics";
-import { JobOptions } from "./types/JobOptions";
-import { Jobs, Modules, ModuleStatus, ModuleClass } from "./types/Modules";
+import { Modules, ModuleStatus, ModuleClass } from "./types/Modules";
 
 export default class ModuleManager {
-	static primaryInstance: ModuleManager;
+	static primaryInstance = new this();
 
 	private modules?: Modules;
 
-	private jobQueue: JobQueue;
-
-	private jobStatistics: JobStatistics;
-
-	/**
-	 * Module Manager
-	 */
-	public constructor() {
-		this.jobQueue = new JobQueue(this);
-		this.jobStatistics = JobStatistics.getPrimaryInstance();
-	}
-
 	/**
 	 * getStatus - Get status of modules
 	 *
@@ -34,49 +19,6 @@ export default class ModuleManager {
 		return status;
 	}
 
-	/**
-	 * getJobsStats - Get statistics of job queue
-	 *
-	 * @returns Job queue statistics
-	 */
-	public getJobsStats() {
-		return this.jobStatistics.getStats();
-	}
-
-	/**
-	 * getJobsStatus - Get status of job queue
-	 *
-	 * @returns Job queue status
-	 */
-	public getJobsStatus() {
-		return this.jobQueue.getStatus();
-	}
-
-	/**
-	 * getQueueStatus - Get status of queued jobs
-	 *
-	 * @returns Job statuses
-	 */
-	public getQueueStatus() {
-		return this.jobQueue.getQueueStatus();
-	}
-
-	/**
-	 * Gets a job from the queue by jobId
-	 *
-	 * @returns Job
-	 */
-	public getJob(jobId: string, recursive = false) {
-		return this.jobQueue.getJob(jobId, recursive);
-	}
-
-	/**
-	 * Gets a list of all jobs running directly in the ModuleManager job queue
-	 */
-	public getJobs() {
-		return this.jobQueue.getJobs();
-	}
-
 	/**
 	 * Gets a module
 	 *
@@ -135,7 +77,7 @@ export default class ModuleManager {
 			await this.shutdown();
 			throw err;
 		});
-		this.jobQueue.resume();
+		JobQueue.getPrimaryInstance().resume();
 	}
 
 	/**
@@ -155,39 +97,11 @@ export default class ModuleManager {
 			);
 	}
 
-	/**
-	 * runJob - Run a job
-	 *
-	 * @param moduleName - Module name
-	 * @param jobName - Job name
-	 * @param params - Params
-	 */
-	public runJob<
-		ModuleNameType extends keyof Jobs & keyof Modules,
-		JobNameType extends keyof Jobs[ModuleNameType] &
-			keyof Omit<Modules[ModuleNameType], keyof BaseModule>,
-		PayloadType extends "payload" extends keyof Jobs[ModuleNameType][JobNameType]
-			? Jobs[ModuleNameType][JobNameType]["payload"] extends undefined
-				? Record<string, never>
-				: Jobs[ModuleNameType][JobNameType]["payload"]
-			: Record<string, never>,
-		ReturnType = "returns" extends keyof Jobs[ModuleNameType][JobNameType]
-			? Jobs[ModuleNameType][JobNameType]["returns"]
-			: never
-	>(
-		moduleName: ModuleNameType,
-		jobName: JobNameType,
-		payload: PayloadType,
-		options?: JobOptions
-	): Promise<ReturnType> {
-		return this.jobQueue.runJob(moduleName, jobName, payload, options);
-	}
-
 	static getPrimaryInstance(): ModuleManager {
 		return this.primaryInstance;
 	}
 
-	static setPrimaryInstance(moduleManager: ModuleManager) {
-		this.primaryInstance = moduleManager;
+	static setPrimaryInstance(instance: ModuleManager) {
+		this.primaryInstance = instance;
 	}
 }

+ 31 - 90
backend/src/main.ts

@@ -1,12 +1,10 @@
 import * as readline from "node:readline";
-import { ObjectId } from "mongodb";
 import ModuleManager from "./ModuleManager";
 import LogBook from "./LogBook";
-import Job from "./Job";
+import JobQueue from "./JobQueue";
 import JobStatistics from "./JobStatistics";
 
-const logBook = new LogBook();
-LogBook.setPrimaryInstance(logBook);
+const logBook = LogBook.getPrimaryInstance();
 
 process.removeAllListeners("uncaughtException");
 process.on("uncaughtException", err => {
@@ -28,11 +26,9 @@ process.on("uncaughtException", err => {
 	});
 });
 
-const jobStatistics = new JobStatistics();
-JobStatistics.setPrimaryInstance(jobStatistics);
+const moduleManager = ModuleManager.getPrimaryInstance();
+const jobQueue = JobQueue.getPrimaryInstance();
 
-const moduleManager = new ModuleManager();
-ModuleManager.setPrimaryInstance(moduleManager);
 moduleManager.startup();
 
 // TOOD remove, or put behind debug option
@@ -41,28 +37,33 @@ moduleManager.startup();
 global.moduleManager = moduleManager;
 // eslint-disable-next-line
 // @ts-ignore
+global.jobQueue = jobQueue;
+// eslint-disable-next-line
+// @ts-ignore
 global.rs = () => {
 	process.exit();
 };
 
-const interval = setInterval(() => {
-	moduleManager
-		.runJob("stations", "addToQueue", { songId: "TestId" })
-		.catch(() => {});
-	moduleManager
-		.runJob("stations", "addA", {}, { priority: 5 })
-		.catch(() => {});
-	// moduleManager
-	// 	.runJob("stations", "", { test: "Test", test2: 123 })
-	// 	.catch(() => {});
-}, 40);
+setTimeout(async () => {
+	const start = Date.now();
+	const x = [];
+	while (x.length < 1) {
+		x.push(jobQueue.runJob("stations", "addC", {}).catch(() => {}));
+	}
+	const y = await Promise.all(x);
+	console.log(y);
+	// const a = await jobQueue.runJob("stations", "addC", {}).catch(() => {});
+	// console.log(555, a);
+	const difference = Date.now() - start;
+	console.log({ difference });
+}, 100);
 
-setTimeout(() => {
-	clearTimeout(interval);
-}, 3000);
+// setTimeout(() => {
+// 	clearTimeout(interval);
+// }, 3000);
 
-setTimeout(async () => {
-	const _id = "6371212daf4e9f8fb14444b2";
+// setTimeout(async () => {
+// 	const _id = "6371212daf4e9f8fb14444b2";
 
 	// logBook.log("Find with no projection");
 	// await moduleManager
@@ -211,7 +212,7 @@ setTimeout(async () => {
 	// 	})
 	// 	.then(console.log)
 	// 	.catch(console.error);
-}, 0);
+// }, 0);
 
 const rl = readline.createInterface({
 	input: process.stdin,
@@ -243,38 +244,6 @@ process.on("SIGINT", shutdown);
 process.on("SIGQUIT", shutdown);
 process.on("SIGTERM", shutdown);
 
-type JobArray = [Job, JobArray[]];
-
-function getNestedChildJobs(job: Job): JobArray {
-	const jobs = job.getJobQueue().getJobs();
-
-	if (jobs.length > 0)
-		return [
-			job,
-			jobs.map((_job: Job) => getNestedChildJobs(_job))
-		] as JobArray;
-
-	return [job, []];
-}
-
-function getJobLines(
-	level: number,
-	[job, jobArrs]: JobArray,
-	seperator = "\t"
-): string[] {
-	const tabs = Array.from({ length: level })
-		.map(() => seperator)
-		.join("");
-	let lines = [
-		`${tabs}${job.getName()} (${job.getStatus()} - ${job.getPriority()} - ${job.getUuid()})`
-	];
-	jobArrs.forEach((jobArr: JobArray) => {
-		lines = [...lines, ...getJobLines(level + 1, jobArr, seperator)];
-	});
-
-	return lines;
-}
-
 const runCommand = (line: string) => {
 	const [command, ...args] = line.split(" ");
 	switch (command) {
@@ -294,16 +263,16 @@ const runCommand = (line: string) => {
 			console.log("Module Manager Status:");
 			console.table(moduleManager.getStatus());
 			console.log("Job Queue Status:");
-			console.table(moduleManager.getJobsStatus());
+			console.table(jobQueue.getStatus());
 			break;
 		}
 		case "stats": {
 			console.log("Job Queue Stats:");
-			console.table(moduleManager.getJobsStats());
+			console.table(JobStatistics.getPrimaryInstance().getStats());
 			break;
 		}
 		case "queue": {
-			const queueStatus = moduleManager.getQueueStatus().queue;
+			const queueStatus = jobQueue.getQueueStatus().queue;
 			if (queueStatus.length === 0)
 				console.log("There are no jobs in the queue.");
 			else
@@ -314,7 +283,7 @@ const runCommand = (line: string) => {
 			break;
 		}
 		case "active": {
-			const activeStatus = moduleManager.getQueueStatus().active;
+			const activeStatus = jobQueue.getQueueStatus().active;
 			if (activeStatus.length === 0)
 				console.log("There are no active jobs.");
 			else console.log(`There are ${activeStatus.length} active jobs.`);
@@ -325,7 +294,7 @@ const runCommand = (line: string) => {
 			if (args.length === 0) console.log("Please specify a jobId");
 			else {
 				const jobId = args[0];
-				const job = moduleManager.getJob(jobId, true);
+				const job = jobQueue.getJob(jobId);
 
 				if (!job) console.log("Job not found");
 				else {
@@ -338,38 +307,10 @@ const runCommand = (line: string) => {
 						moduleStatus: job?.getModule().getStatus()
 					};
 					console.table(jobInfo);
-
-					// Gets all child jobs of the current job, including the current job, nested
-					const jobArrs = getNestedChildJobs(job);
-
-					const jobLines = getJobLines(0, jobArrs);
-
-					jobLines.forEach(jobLine => {
-						console.log(jobLine);
-					});
 				}
 			}
 			break;
 		}
-		case "jobtree": {
-			const jobs = moduleManager.getJobs();
-
-			let jobLines: string[] = [];
-
-			jobs.forEach(job => {
-				// Gets all child jobs of the current job, including the current job, nested
-				const jobArrs = getNestedChildJobs(job);
-
-				jobLines = [...jobLines, ...getJobLines(0, jobArrs)];
-			});
-
-			console.log("List of jobs:");
-			jobLines.forEach(jobLine => {
-				console.log(jobLine);
-			});
-
-			break;
-		}
 		case "eval": {
 			const evalCommand = args.join(" ");
 			console.log(`Running eval command: ${evalCommand}`);

+ 1 - 0
backend/src/types/JobOptions.ts

@@ -1,4 +1,5 @@
 export type JobOptions = {
 	priority?: number;
 	runDirectly?: boolean;
+	longJob?: string;
 };