feat: add Job Monitor page with cron job logging and Selenium queue status

This commit is contained in:
ff
2026-04-13 00:32:18 -04:00
parent 034c0fa993
commit 11a6d2e5a7
85 changed files with 3046 additions and 12 deletions

View File

@@ -19,6 +19,7 @@ import paymentOcrRoutes from "./paymentOcrExtraction";
import cloudStorageRoutes from "./cloud-storage";
import paymentsReportsRoutes from "./payments-reports";
import exportPaymentsReportsRoutes from "./export-payments-reports";
import jobMonitorRoutes from "./job-monitor";
const router = Router();
@@ -42,5 +43,6 @@ router.use("/payment-ocr", paymentOcrRoutes);
router.use("/cloud-storage", cloudStorageRoutes);
router.use("/payments-reports", paymentsReportsRoutes);
router.use("/export-payments-reports", exportPaymentsReportsRoutes);
router.use("/job-monitor", jobMonitorRoutes);
export default router;

View File

@@ -0,0 +1,51 @@
import { Router, Request, Response } from "express";
import axios from "axios";
import { cronJobLogStorage } from "../storage/cron-job-log-storage";
const router = Router();
const SELENIUM_BASE_URL =
process.env.SELENIUM_AGENT_BASE_URL || "http://localhost:5002";
// GET /api/job-monitor/summary
// Returns last run per cron job + recent history
router.get("/summary", async (_req: Request, res: Response) => {
try {
const [lastRuns, recentLogs] = await Promise.all([
cronJobLogStorage.getLastRunPerJob(),
cronJobLogStorage.getRecentLogs(30),
]);
res.json({ lastRuns, recentLogs });
} catch (err) {
console.error("job-monitor/summary error:", err);
res.status(500).json({ error: "Failed to fetch cron job summary" });
}
});
// GET /api/job-monitor/failed
// Returns recent failed job logs
router.get("/failed", async (_req: Request, res: Response) => {
try {
const failed = await cronJobLogStorage.getFailedLogs(20);
res.json(failed);
} catch (err) {
console.error("job-monitor/failed error:", err);
res.status(500).json({ error: "Failed to fetch failed jobs" });
}
});
// GET /api/job-monitor/selenium-status
// Proxies the Selenium service /status endpoint
router.get("/selenium-status", async (_req: Request, res: Response) => {
try {
const response = await axios.get(`${SELENIUM_BASE_URL}/status`, {
timeout: 4000,
});
res.json({ online: true, ...response.data });
} catch (err) {
// Service may be offline — return gracefully
res.json({ online: false, active_jobs: 0, queued_jobs: 0, status: "offline" });
}
});
export default router;