diff --git a/server/controllers/monitorController.js b/server/controllers/monitorController.js index e8eaeb106..1247e4509 100755 --- a/server/controllers/monitorController.js +++ b/server/controllers/monitorController.js @@ -550,10 +550,8 @@ class MonitorController { }) ); - // Delete the old job(editedMonitor has the same ID as the old monitor) - await this.jobQueue.deleteJob(monitorBeforeEdit); - // Add the new job back to the queue - await this.jobQueue.addJob(editedMonitor._id, editedMonitor); + await this.jobQueue.updateJob(editedMonitor); + return res.success({ msg: this.stringService.monitorEdit, data: editedMonitor, @@ -595,8 +593,8 @@ class MonitorController { { new: true } ); monitor.isActive === true - ? await this.jobQueue.addJob(monitor._id, monitor) - : await this.jobQueue.deleteJob(monitor); + ? await this.jobQueue.resumeJob(monitor._id, monitor) + : await this.jobQueue.pauseJob(monitor); return res.success({ msg: monitor.isActive diff --git a/server/controllers/queueController.js b/server/controllers/queueController.js index be3d764e7..b1a7badee 100755 --- a/server/controllers/queueController.js +++ b/server/controllers/queueController.js @@ -46,18 +46,6 @@ class JobQueueController { } }; - obliterateQueue = async (req, res, next) => { - try { - await this.jobQueue.obliterate(); - return res.success({ - msg: this.stringService.queueObliterate, - }); - } catch (error) { - next(handleError(error, SERVICE_NAME, "obliterateQueue")); - return; - } - }; - flushQueue = async (req, res, next) => { try { const result = await this.jobQueue.flushQueues(); diff --git a/server/index.js b/server/index.js index eea5b015a..dccf77c9b 100755 --- a/server/index.js +++ b/server/index.js @@ -50,6 +50,9 @@ import JobQueue from "./service/JobQueue/JobQueue.js"; import JobQueueHelper from "./service/JobQueue/JobQueueHelper.js"; import { Queue, Worker } from "bullmq"; +import PulseQueue from "./service/PulseQueue/PulseQueue.js"; +import PulseQueueHelper from "./service/PulseQueue/PulseQueueHelper.js"; + //Network service and dependencies import NetworkService from "./service/networkService.js"; import axios from "axios"; @@ -183,25 +186,40 @@ const startApp = async () => { const redisService = new RedisService({ Redis: IORedis, logger }); - const jobQueueHelper = new JobQueueHelper({ - redisService, - Queue, - Worker, - logger, + // const jobQueueHelper = new JobQueueHelper({ + // redisService, + // Queue, + // Worker, + // logger, + // db, + // networkService, + // statusService, + // notificationService, + // }); + // const jobQueue = await JobQueue.create({ + // db, + // jobQueueHelper, + // logger, + // stringService, + // }); + + const pulseQueueHelper = new PulseQueueHelper({ db, + logger, networkService, statusService, notificationService, }); - const jobQueue = await JobQueue.create({ + const pulseQueue = await PulseQueue.create({ + appSettings, db, - jobQueueHelper, + pulseQueueHelper, logger, - stringService, }); // Register services - ServiceRegistry.register(JobQueue.SERVICE_NAME, jobQueue); + // ServiceRegistry.register(JobQueue.SERVICE_NAME, jobQueue); + ServiceRegistry.register(JobQueue.SERVICE_NAME, pulseQueue); ServiceRegistry.register(MongoDB.SERVICE_NAME, db); ServiceRegistry.register(SettingsService.SERVICE_NAME, settingsService); ServiceRegistry.register(EmailService.SERVICE_NAME, emailService); diff --git a/server/package-lock.json b/server/package-lock.json index 7bf4bfc78..3fd675af3 100755 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@pulsecron/pulse": "1.6.8", "axios": "^1.7.2", "bcryptjs": "3.0.2", "bullmq": "5.41.2", @@ -1012,6 +1013,37 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "license": "BSD-3-Clause" }, + "node_modules/@pulsecron/pulse": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@pulsecron/pulse/-/pulse-1.6.8.tgz", + "integrity": "sha512-fg9sT/pfpZTlUYr/ktDu6om6XEm2zmulcZ8TP4JZa+Dmol7/35mMKzDwT1H5a0AUcxiFIRfB4KOpkJ+BI2fgmg==", + "license": "MIT", + "dependencies": { + "cron-parser": "^4.9.0", + "date.js": "~0.3.3", + "debug": "~4.3.4", + "human-interval": "~2.0.1", + "moment-timezone": "^0.5.45", + "mongodb": "^6.5.0" + } + }, + "node_modules/@pulsecron/pulse/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/@scarf/scarf": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", @@ -2394,6 +2426,30 @@ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", "license": "CC0-1.0" }, + "node_modules/date.js": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/date.js/-/date.js-0.3.3.tgz", + "integrity": "sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw==", + "license": "MIT", + "dependencies": { + "debug": "~3.1.0" + } + }, + "node_modules/date.js/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/date.js/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -3664,6 +3720,15 @@ "node": ">= 6" } }, + "node_modules/human-interval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/human-interval/-/human-interval-2.0.1.tgz", + "integrity": "sha512-r4Aotzf+OtKIGQCB3odUowy4GfUDTy3aTWTfLd7ZF2gBCy3XW3v/dJLRefZnOFFnjqs5B1TypvS8WarpBkYUNQ==", + "license": "MIT", + "dependencies": { + "numbered": "^1.1.0" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -4986,6 +5051,27 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/mongodb": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.13.0.tgz", @@ -5385,6 +5471,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/numbered": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/numbered/-/numbered-1.1.0.tgz", + "integrity": "sha512-pv/ue2Odr7IfYOO0byC1KgBI10wo5YDauLhxY6/saNzAdAs0r1SotGCPzzCLNPL0xtrAwWRialLu23AAu9xO1g==", + "license": "MIT" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7099,9 +7191,9 @@ } }, "node_modules/tar-fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", "license": "MIT", "dependencies": { "chownr": "^1.1.1", diff --git a/server/package.json b/server/package.json index 097cf4443..51e7cd218 100755 --- a/server/package.json +++ b/server/package.json @@ -16,6 +16,7 @@ "author": "", "license": "ISC", "dependencies": { + "@pulsecron/pulse": "1.6.8", "axios": "^1.7.2", "bcryptjs": "3.0.2", "bullmq": "5.41.2", diff --git a/server/routes/queueRoute.js b/server/routes/queueRoute.js index 38ac32a26..dc9b40917 100755 --- a/server/routes/queueRoute.js +++ b/server/routes/queueRoute.js @@ -25,12 +25,6 @@ class QueueRoutes { this.queueController.addJob ); - this.router.post( - "/obliterate", - isAllowed(["admin", "superadmin"]), - this.queueController.obliterateQueue - ); - this.router.post( "/flush", isAllowed(["admin", "superadmin"]), diff --git a/server/service/JobQueue/JobQueue.js b/server/service/JobQueue/JobQueue.js index 32d531809..ed662e322 100644 --- a/server/service/JobQueue/JobQueue.js +++ b/server/service/JobQueue/JobQueue.js @@ -51,7 +51,6 @@ class JobQueue { } }) ); - this.healthCheckInterval = setInterval(async () => { try { const queueHealthChecks = await this.checkQueueHealth(); @@ -116,6 +115,14 @@ class JobQueue { }); } + pauseJob = async (monitor) => { + this.deleteJob(monitor); + }; + + resumeJob = async (monitor) => { + this.addJob(monitor._id, monitor); + }; + async addJob(jobName, monitor) { this.logger.info({ message: `Adding job ${monitor?.url ?? "No URL"}`, @@ -181,6 +188,11 @@ class JobQueue { } } + async updateJob(monitor) { + await this.deleteJob(monitor); + await this.addJob(monitor._id, monitor); + } + async getJobs() { try { let stats = {}; diff --git a/server/service/JobQueue/JobQueueHelper.js b/server/service/JobQueue/JobQueueHelper.js index de1e00fb8..9e08e2cf1 100644 --- a/server/service/JobQueue/JobQueueHelper.js +++ b/server/service/JobQueue/JobQueueHelper.js @@ -254,7 +254,8 @@ class JobQueueHelper { // Get the current status await job.updateProgress(30); - const networkResponse = await this.networkService.getStatus(job); + const monitor = job.data; + const networkResponse = await this.networkService.getStatus(monitor); if ( job.data.type === "distributed_http" || job.data.type === "distributed_test" @@ -271,14 +272,17 @@ class JobQueueHelper { // Handle status change await job.updateProgress(60); - const { monitor, statusChanged, prevStatus } = - await this.statusService.updateStatus(networkResponse); + const { + monitor: updatedMonitor, + statusChanged, + prevStatus, + } = await this.statusService.updateStatus(networkResponse); // Handle notifications await job.updateProgress(80); this.notificationService .handleNotifications({ ...networkResponse, - monitor, + monitor: updatedMonitor, prevStatus, statusChanged, }) diff --git a/server/service/PulseQueue/PulseQueue.js b/server/service/PulseQueue/PulseQueue.js new file mode 100644 index 000000000..fd420400f --- /dev/null +++ b/server/service/PulseQueue/PulseQueue.js @@ -0,0 +1,191 @@ +import { Pulse } from "@pulsecron/pulse"; +import { ObjectId } from "mongodb"; + +const SERVICE_NAME = "PulseQueue"; +class PulseQueue { + static SERVICE_NAME = SERVICE_NAME; + + constructor({ appSettings, db, pulseQueueHelper, logger }) { + this.db = db; + this.appSettings = appSettings; + this.pulseQueueHelper = pulseQueueHelper; + this.logger = logger; + } + + static async create({ appSettings, db, pulseQueueHelper, logger }) { + const instance = new PulseQueue({ appSettings, db, pulseQueueHelper, logger }); + await instance.init(); + return instance; + } + + // **************************************** + // Core methods + // **************************************** + init = async () => { + try { + const mongoConnectionString = + this.appSettings.dbConnectionString || "mongodb://localhost:27017/uptime_db"; + this.pulse = new Pulse({ db: { address: mongoConnectionString } }); + await this.pulse.start(); + this.pulse.define("monitor-job", this.pulseQueueHelper.getMonitorJob(), {}); + + const monitors = await this.db.getAllMonitors(); + for (const monitor of monitors) { + await this.addJob(monitor._id, monitor); + } + return true; + } catch (error) { + this.logger.error({ + message: "Failed to initialize PulseQueue", + service: SERVICE_NAME, + method: "init", + details: error, + }); + return false; + } + }; + + addJob = async (monitorId, monitor) => { + this.logger.debug({ + message: `Adding job ${monitor?.url ?? "No URL"}`, + service: SERVICE_NAME, + method: "addJob", + }); + const intervalInSeconds = monitor.interval / 1000; + const job = this.pulse.create("monitor-job", { + monitor, + }); + job.unique({ "data.monitor._id": monitor._id }); + job.attrs.jobId = monitorId.toString(); + job.repeatEvery(`${intervalInSeconds} seconds`); + await job.save(); + }; + + deleteJob = async (monitor) => { + this.logger.debug({ + message: `Deleting job ${monitor?.url ?? "No URL"}`, + service: SERVICE_NAME, + method: "deleteJob", + }); + await this.pulse.cancel({ + "data.monitor._id": monitor._id, + }); + }; + + pauseJob = async (monitor) => { + const result = await this.pulse.disable({ + "data.monitor._id": monitor._id, + }); + + if (result.length < 1) { + throw new Error("Failed to pause monitor"); + } + + this.logger.debug({ + message: `Paused monitor ${monitor._id}`, + service: SERVICE_NAME, + method: "pauseJob", + }); + }; + + resumeJob = async (monitor) => { + const result = await this.pulse.enable({ + "data.monitor._id": monitor._id, + }); + + if (result.length < 1) { + throw new Error("Failed to resume monitor"); + } + + this.logger.debug({ + message: `Resumed monitor ${monitor._id}`, + service: SERVICE_NAME, + method: "resumeJob", + }); + }; + + updateJob = async (monitor) => { + const jobs = await this.pulse.jobs({ + "data.monitor._id": monitor._id, + }); + + const job = jobs[0]; + if (!job) { + throw new Error("Job not found"); + } + + const intervalInSeconds = monitor.interval / 1000; + job.repeatEvery(`${intervalInSeconds} seconds`); + job.attrs.data.monitor = monitor; + await job.save(); + }; + + shutdown = async () => { + this.logger.info({ + message: "Shutting down JobQueue", + service: SERVICE_NAME, + method: "shutdown", + }); + await this.pulse.stop(); + }; + + // **************************************** + // Diagnostic methods + // **************************************** + + getMetrics = async () => { + const jobs = await this.pulse.jobs(); + const metrics = jobs.reduce( + (acc, job) => { + acc.jobs++; + if (job.attrs.failCount > 0 && job.attrs.failedAt >= job.attrs.lastFinishedAt) { + acc.failingJobs++; + } + if (job.attrs.lockedAt) { + acc.activeJobs++; + } + if (job.attrs.failCount > 0) { + acc.jobsWithFailures.push({ + monitorId: job.attrs.data.monitor._id, + monitorUrl: job.attrs.data.monitor.url, + failCount: job.attrs.failCount, + failReason: job.attrs.failReason, + }); + } + return acc; + }, + { jobs: 0, activeJobs: 0, failingJobs: 0, jobsWithFailures: [] } + ); + return metrics; + }; + + getJobs = async () => { + const jobs = await this.pulse.jobs(); + return jobs.map((job) => { + return { + monitorId: job.attrs.data.monitor._id, + monitorUrl: job.attrs.data.monitor.url, + lockedAt: job.attrs.lockedAt, + runCount: job.attrs.runCount || 0, + failCount: job.attrs.failCount || 0, + failReason: job.attrs.failReason, + }; + }); + }; + + flushQueues = async () => { + const cancelRes = await this.pulse.cancel(); + await this.pulse.stop(); + const initRes = await this.init(); + return { + flushedJobs: cancelRes, + initSuccess: initRes, + }; + }; + + obliterate = async () => { + await this.flushQueues(); + }; +} + +export default PulseQueue; diff --git a/server/service/PulseQueue/PulseQueueHelper.js b/server/service/PulseQueue/PulseQueueHelper.js new file mode 100644 index 000000000..01207d211 --- /dev/null +++ b/server/service/PulseQueue/PulseQueueHelper.js @@ -0,0 +1,106 @@ +const SERVICE_NAME = "PulseQueueHelper"; + +class PulseQueueHelper { + constructor({ db, logger, networkService, statusService, notificationService }) { + this.db = db; + this.logger = logger; + this.networkService = networkService; + this.statusService = statusService; + this.notificationService = notificationService; + } + + getMonitorJob = () => { + return async (job) => { + try { + const monitor = job.attrs.data.monitor; + const monitorId = job.attrs.data.monitor._id; + if (!monitorId) { + throw new Error("No monitor id"); + } + + const maintenanceWindowActive = await this.isInMaintenanceWindow(monitorId); + if (maintenanceWindowActive) { + this.logger.info({ + message: `Monitor ${monitorId} is in maintenance window`, + service: SERVICE_NAME, + method: "getMonitorJob", + }); + return; + } + + const networkResponse = await this.networkService.getStatus(monitor); + if (monitor.type === "distributed_http" || monitor.type === "distributed_test") { + await job.updateProgress(100); + return true; + } + + if (!networkResponse) { + throw new Error("No network response"); + } + + const { + monitor: updatedMonitor, + statusChanged, + prevStatus, + } = await this.statusService.updateStatus(networkResponse); + + this.notificationService + .handleNotifications({ + ...networkResponse, + monitor: updatedMonitor, + prevStatus, + statusChanged, + }) + .catch((error) => { + this.logger.error({ + message: error.message, + service: SERVICE_NAME, + method: "getMonitorJob", + details: `Error sending notifications for job ${job.id}: ${error.message}`, + stack: error.stack, + }); + }); + } catch (error) { + this.logger.warn({ + message: error.message, + service: error.service || SERVICE_NAME, + method: error.method || "getMonitorJob", + stack: error.stack, + }); + throw error; + } + }; + }; + + async isInMaintenanceWindow(monitorId) { + const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId(monitorId); + // Check for active maintenance window: + const maintenanceWindowIsActive = maintenanceWindows.reduce((acc, window) => { + if (window.active) { + const start = new Date(window.start); + const end = new Date(window.end); + const now = new Date(); + const repeatInterval = window.repeat || 0; + + // If start is < now and end > now, we're in maintenance + if (start <= now && end >= now) return true; + + // If maintenance window was set in the past with a repeat, + // we need to advance start and end to see if we are in range + + while (start < now && repeatInterval !== 0) { + start.setTime(start.getTime() + repeatInterval); + end.setTime(end.getTime() + repeatInterval); + if (start <= now && end >= now) { + return true; + } + } + return false; + } + return acc; + }, false); + return maintenanceWindowIsActive; + } +} + +export default PulseQueueHelper; diff --git a/server/service/networkService.js b/server/service/networkService.js index a023ffadd..9e5e83d24 100755 --- a/server/service/networkService.js +++ b/server/service/networkService.js @@ -125,7 +125,7 @@ class NetworkService { * @property {number} code - The response code (200 if successful, error code otherwise). * @property {string} message - The message indicating the result of the HTTP request. */ - async requestHttp(job) { + async requestHttp(monitor) { try { const { url, @@ -138,7 +138,7 @@ class NetworkService { jsonPath, matchMethod, expectedValue, - } = job.data; + } = monitor; const config = {}; secret !== undefined && (config.headers = { Authorization: `Bearer ${secret}` }); @@ -248,10 +248,10 @@ class NetworkService { * @property {number} code - The response code (200 if successful, error code otherwise). * @property {string} message - The message indicating the result of the PageSpeed request. */ - async requestPagespeed(job) { + async requestPagespeed(monitor) { try { - const url = job.data.url; - const updatedJob = { ...job }; + const url = monitor.url; + const updatedMonitor = { ...monitor }; let pagespeedUrl = `https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${url}&category=seo&category=accessibility&category=best-practices&category=performance`; const dbSettings = await this.settingsService.getDBSettings(); @@ -266,8 +266,8 @@ class NetworkService { }); return; } - updatedJob.data.url = pagespeedUrl; - return await this.requestHttp(updatedJob); + updatedMonitor.url = pagespeedUrl; + return await this.requestHttp(updatedMonitor); } catch (error) { error.service = this.SERVICE_NAME; error.method = "requestPagespeed"; @@ -292,9 +292,9 @@ class NetworkService { * @property {number} code - The response code (200 if successful, error code otherwise). * @property {string} message - The message indicating the result of the hardware status request. */ - async requestHardware(job) { + async requestHardware(monitor) { try { - return await this.requestHttp(job); + return await this.requestHttp(monitor); } catch (error) { error.service = this.SERVICE_NAME; error.method = "requestHardware"; @@ -318,7 +318,7 @@ class NetworkService { * @property {number} code - The response code (200 if successful, error code otherwise). * @property {string} message - The message indicating the result of the Docker inspection. */ - async requestDocker(job) { + async requestDocker(monitor) { try { const docker = new this.Docker({ socketPath: "/var/run/docker.sock", @@ -326,19 +326,19 @@ class NetworkService { }); const containers = await docker.listContainers({ all: true }); - const containerExists = containers.some((c) => c.Id.startsWith(job.data.url)); + const containerExists = containers.some((c) => c.Id.startsWith(monitor.url)); if (!containerExists) { throw new Error(this.stringService.dockerNotFound); } - const container = docker.getContainer(job.data.url); + const container = docker.getContainer(monitor.url); const { response, responseTime, error } = await this.timeRequest(() => container.inspect() ); const dockerResponse = { - monitorId: job.data._id, - type: job.data.type, + monitorId: monitor._id, + type: monitor.type, responseTime, }; @@ -360,9 +360,9 @@ class NetworkService { } } - async requestPort(job) { + async requestPort(monitor) { try { - const { url, port } = job.data; + const { url, port } = monitor; const { response, responseTime, error } = await this.timeRequest(async () => { return new Promise((resolve, reject) => { const socket = this.net.createConnection( @@ -391,8 +391,8 @@ class NetworkService { }); const portResponse = { - monitorId: job.data._id, - type: job.data.type, + monitorId: monitor._id, + type: monitor.type, responseTime, }; @@ -414,9 +414,8 @@ class NetworkService { } } - async requestDistributedHttp(job) { + async requestDistributedHttp(monitor) { try { - const monitor = job.data; const CALLBACK_URL = process.env.CALLBACK_URL; const response = await this.axios.post( @@ -503,23 +502,23 @@ class NetworkService { * @returns {Promise} The response object from the appropriate request method. * @throws {Error} Throws an error if the job type is unsupported. */ - async getStatus(job) { - const type = job?.data?.type ?? "unknown"; + async getStatus(monitor) { + const type = monitor.type ?? "unknown"; switch (type) { case this.TYPE_PING: - return await this.requestPing(job); + return await this.requestPing(monitor); case this.TYPE_HTTP: - return await this.requestHttp(job); + return await this.requestHttp(monitor); case this.TYPE_PAGESPEED: - return await this.requestPagespeed(job); + return await this.requestPagespeed(monitor); case this.TYPE_HARDWARE: - return await this.requestHardware(job); + return await this.requestHardware(monitor); case this.TYPE_DOCKER: - return await this.requestDocker(job); + return await this.requestDocker(monitor); case this.TYPE_PORT: - return await this.requestPort(job); + return await this.requestPort(monitor); case this.TYPE_DISTRIBUTED_HTTP: - return await this.requestDistributedHttp(job); + return await this.requestDistributedHttp(monitor); case this.TYPE_DISTRIBUTED_TEST: return; default: diff --git a/server/service/statusService.js b/server/service/statusService.js index a53552717..ebd3e2b41 100755 --- a/server/service/statusService.js +++ b/server/service/statusService.js @@ -228,6 +228,12 @@ class StatusService { if (type === "pagespeed") { if (typeof payload === "undefined") { + this.logger.warn({ + message: "Failed to build check", + service: this.SERVICE_NAME, + method: "buildCheck", + details: "empty payload", + }); return undefined; } const categories = payload?.lighthouseResult?.categories ?? {}; @@ -287,9 +293,11 @@ class StatusService { } catch (error) { this.logger.error({ message: error.message, - service: this.SERVICE_NAME, - method: "insertCheck", - details: `Error inserting check for monitor: ${networkResponse?.monitorId}`, + service: error.service || this.SERVICE_NAME, + method: error.method || "insertCheck", + details: + error.details || + `Error inserting check for monitor: ${networkResponse?.monitorId}`, stack: error.stack, }); }