reafactored data mart and added better job monitor
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import { jobAuditLog } from "backend/db/schema/auditLog.schema.js";
|
||||
import { Cron } from "croner";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { db } from "../db/db.controller.js";
|
||||
import { createLogger } from "../logger/logger.controller.js";
|
||||
|
||||
// example createJob
|
||||
@@ -16,15 +19,22 @@ export interface JobInfo {
|
||||
// Store running cronjobs
|
||||
export const runningCrons: Record<string, Cron> = {};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name Name of the job we want to run
|
||||
* @param schedule Cron expression (example: `*\/5 * * * * *`)
|
||||
* @param task Async function that will run
|
||||
*/
|
||||
export const createCronJob = async (
|
||||
name: string,
|
||||
schedule: string, // cron string with 8 8 IE: */5 * * * * * every 5th second
|
||||
task?: () => Promise<void>, // what function are we passing over
|
||||
task: () => Promise<void>, // what function are we passing over
|
||||
) => {
|
||||
// get the timezone based on the os timezone set
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const log = createLogger({ module: "system", subModule: "croner" });
|
||||
|
||||
// Destroy existing job if it exists
|
||||
// Destroy existing job if it exist
|
||||
if (runningCrons[name]) {
|
||||
runningCrons[name].stop();
|
||||
}
|
||||
@@ -37,10 +47,48 @@ export const createCronJob = async (
|
||||
catch: true, // Prevents unhandled rejections
|
||||
name: name,
|
||||
},
|
||||
task,
|
||||
);
|
||||
async () => {
|
||||
const startedAt = new Date();
|
||||
const start = Date.now();
|
||||
|
||||
const log = createLogger({ module: "system", subModule: "croner" });
|
||||
let executionId: string = "";
|
||||
|
||||
try {
|
||||
const [execution] = await db
|
||||
.insert(jobAuditLog)
|
||||
.values({
|
||||
jobName: name,
|
||||
startedAt,
|
||||
status: "running",
|
||||
})
|
||||
.returning();
|
||||
|
||||
executionId = execution?.id as string;
|
||||
|
||||
await task?.();
|
||||
|
||||
// tell it we done
|
||||
await db
|
||||
.update(jobAuditLog)
|
||||
.set({
|
||||
finishedAt: new Date(),
|
||||
durationMs: Date.now() - start,
|
||||
status: "success",
|
||||
})
|
||||
.where(eq(jobAuditLog.id, executionId));
|
||||
} catch (e: any) {
|
||||
if (executionId) {
|
||||
await db.update(jobAuditLog).set({
|
||||
finishedAt: new Date(),
|
||||
durationMs: Date.now() - start,
|
||||
status: "error",
|
||||
errorMessage: e.message,
|
||||
errorStack: e.stack,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
log.info({}, `A job for ${name} was just created.`);
|
||||
};
|
||||
|
||||
19
backend/utils/cronnerActiveJobs.route.ts
Normal file
19
backend/utils/cronnerActiveJobs.route.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Router } from "express";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { getAllJobs } from "./croner.utils.js";
|
||||
|
||||
const r = Router();
|
||||
|
||||
r.get("/", async (_, res) => {
|
||||
return apiReturn(res, {
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "utils",
|
||||
subModule: "jobs",
|
||||
message: "All current Jobs",
|
||||
data: getAllJobs(),
|
||||
status: 200,
|
||||
});
|
||||
});
|
||||
|
||||
export default r;
|
||||
63
backend/utils/cronnerStatusChange.ts
Normal file
63
backend/utils/cronnerStatusChange.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Router } from "express";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { getAllJobs, resumeCronJob, stopCronJob } from "./croner.utils.js";
|
||||
|
||||
const r = Router();
|
||||
|
||||
r.patch("/:status", async (req, res) => {
|
||||
const { status } = req.params;
|
||||
const body = req.body;
|
||||
|
||||
if (!body.name) {
|
||||
return apiReturn(res, {
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "utils",
|
||||
subModule: "jobs",
|
||||
message: "Missing manadatory name ",
|
||||
data: getAllJobs(),
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const statusCheck = ["start", "stop"];
|
||||
if (!statusCheck.includes(status)) {
|
||||
return apiReturn(res, {
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "utils",
|
||||
subModule: "jobs",
|
||||
message: "You have passed an invalid option please try again. ",
|
||||
data: getAllJobs(),
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (status === "start") {
|
||||
resumeCronJob(body.name);
|
||||
return apiReturn(res, {
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "utils",
|
||||
subModule: "jobs",
|
||||
message: `${name} was restarted`,
|
||||
data: getAllJobs(),
|
||||
status: 200,
|
||||
});
|
||||
}
|
||||
|
||||
if (status === "stop") {
|
||||
stopCronJob(body.name);
|
||||
return apiReturn(res, {
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "utils",
|
||||
subModule: "jobs",
|
||||
message: `${body.name} was stopped`,
|
||||
data: getAllJobs(),
|
||||
status: 200,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default r;
|
||||
3
backend/utils/delay.utils.ts
Normal file
3
backend/utils/delay.utils.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const delay = (ms: number) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
};
|
||||
@@ -1,16 +1,8 @@
|
||||
import type { Express } from "express";
|
||||
import { getAllJobs } from "./croner.utils.js";
|
||||
import { apiReturn } from "./returnHelper.utils.js";
|
||||
|
||||
import getActiveJobs from "./cronnerActiveJobs.route.js";
|
||||
import jobStatusChange from "./cronnerStatusChange.js";
|
||||
export const setupUtilsRoutes = (baseUrl: string, app: Express) => {
|
||||
app.get(`${baseUrl}/api/utils`, (_, res) => {
|
||||
return apiReturn(res, {
|
||||
success: true,
|
||||
level: "info",
|
||||
module: "utils",
|
||||
subModule: "jobs",
|
||||
message: "All current Jobs",
|
||||
data: getAllJobs(),
|
||||
status: 200,
|
||||
});
|
||||
});
|
||||
app.use(`${baseUrl}/api/utils/croner`, getActiveJobs);
|
||||
app.use(`${baseUrl}/api/utils/croner`, jobStatusChange);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user