mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-09 02:20:47 -05:00
Refactored notifications from Check model to NetworkService
This commit is contained in:
@@ -263,69 +263,10 @@ const getMonitorStatsById = async (req) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getMonitorById = async (req, res) => {
|
||||
const getMonitorById = async (monitorId) => {
|
||||
try {
|
||||
const { monitorId } = req.params;
|
||||
let { status, limit, sortOrder, filter, numToDisplay, normalize } =
|
||||
req.query;
|
||||
|
||||
const filterLookup = {
|
||||
day: new Date(new Date().setDate(new Date().getDate() - 1)),
|
||||
week: new Date(new Date().setDate(new Date().getDate() - 7)),
|
||||
month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
|
||||
};
|
||||
|
||||
// This effectively removes limit, returning all checks
|
||||
if (limit === undefined) limit = 0;
|
||||
|
||||
// Default sort order is newest -> oldest
|
||||
if (sortOrder === "asc") {
|
||||
sortOrder = 1;
|
||||
} else if (sortOrder === "desc") {
|
||||
sortOrder = -1;
|
||||
} else sortOrder = -1;
|
||||
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
|
||||
const checksQuery = { monitorId: monitor._id };
|
||||
|
||||
if (status !== undefined) {
|
||||
checksQuery.status = status;
|
||||
}
|
||||
|
||||
// Filter checks by "day", "week", or "month"
|
||||
if (filter !== undefined) {
|
||||
checksQuery.createdAt = { $gte: filterLookup[filter] };
|
||||
}
|
||||
|
||||
// Determine model type
|
||||
let model =
|
||||
monitor.type === "http" || monitor.type === "ping"
|
||||
? Check
|
||||
: PageSpeedCheck;
|
||||
|
||||
let checks = await model
|
||||
.find(checksQuery)
|
||||
.sort({
|
||||
createdAt: sortOrder,
|
||||
})
|
||||
.limit(limit);
|
||||
|
||||
// If more than numToDisplay checks, pick every nth check
|
||||
if (numToDisplay !== undefined && checks && checks.length > numToDisplay) {
|
||||
const n = Math.ceil(checks.length / numToDisplay);
|
||||
checks = checks.filter(
|
||||
(_, index) => index % n === 0 || index === checks.length - 1
|
||||
);
|
||||
}
|
||||
|
||||
// Normalize checks if requested
|
||||
if (normalize !== undefined) {
|
||||
checks = NormalizeData(checks, 1, 100);
|
||||
}
|
||||
const notifications = await Notification.find({ monitorId: monitor._id });
|
||||
const monitorWithChecks = { ...monitor.toObject(), checks, notifications };
|
||||
return monitorWithChecks;
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
+3
-1
@@ -16,6 +16,7 @@ const maintenanceWindowRouter = require("./routes/maintenanceWindowRoute");
|
||||
const { connectDbAndRunServer } = require("./configs/db");
|
||||
const queueRouter = require("./routes/queueRoute");
|
||||
const JobQueue = require("./service/jobQueue");
|
||||
const NetworkService = require("./service/networkService");
|
||||
const EmailService = require("./service/emailService");
|
||||
const PageSpeedService = require("./service/pageSpeedService");
|
||||
|
||||
@@ -114,8 +115,9 @@ const startApp = async () => {
|
||||
|
||||
// Create services
|
||||
await connectDbAndRunServer(app, db);
|
||||
const jobQueue = await JobQueue.createJobQueue(db);
|
||||
const emailService = new EmailService();
|
||||
const networkService = new NetworkService(db, emailService);
|
||||
const jobQueue = await JobQueue.createJobQueue(db, networkService);
|
||||
const pageSpeedService = new PageSpeedService();
|
||||
|
||||
const cleanup = async () => {
|
||||
|
||||
@@ -69,61 +69,4 @@ const CheckSchema = mongoose.Schema(
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Pre-save middleware to handle status change notifications.
|
||||
*
|
||||
* This middleware checks if the status of the monitor associated
|
||||
* with the check has changed and sends notifications if necessary.
|
||||
*/
|
||||
CheckSchema.pre("save", async function (next) {
|
||||
try {
|
||||
const monitor = await mongoose.model("Monitor").findById(this.monitorId);
|
||||
|
||||
if (monitor) {
|
||||
const notifications = await Notification.find({
|
||||
monitorId: this.monitorId,
|
||||
});
|
||||
|
||||
// Check if there are any notifications
|
||||
|
||||
// Only send email if monitor status has changed
|
||||
if (monitor.status !== this.status) {
|
||||
const emailService = new EmailService();
|
||||
|
||||
let template = "";
|
||||
let status = "";
|
||||
if (monitor.status === true && this.status === false) {
|
||||
template = "serverIsDownTemplate";
|
||||
status = "down";
|
||||
}
|
||||
|
||||
if (monitor.status === false && this.status === true) {
|
||||
// Notify users that the monitor is up
|
||||
template = "serverIsUpTemplate";
|
||||
status = "up";
|
||||
}
|
||||
|
||||
for (const notification of notifications) {
|
||||
if (notification.type === "email") {
|
||||
await emailService.buildAndSendEmail(
|
||||
template,
|
||||
{ monitorName: monitor.name, monitorUrl: monitor.url },
|
||||
notification.address,
|
||||
`Monitor ${monitor.name} is ${status}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Update monitor status
|
||||
monitor.status = this.status;
|
||||
await monitor.save();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model("Check", CheckSchema);
|
||||
|
||||
@@ -16,7 +16,7 @@ class JobQueue {
|
||||
* @constructor
|
||||
* @throws {Error}
|
||||
*/
|
||||
constructor() {
|
||||
constructor(networkService) {
|
||||
this.queue = new Queue(QUEUE_NAME, {
|
||||
connection,
|
||||
});
|
||||
@@ -32,11 +32,11 @@ class JobQueue {
|
||||
* @returns {Promise<JobQueue>} - Returns a new JobQueue
|
||||
*
|
||||
*/
|
||||
static async createJobQueue(db) {
|
||||
static async createJobQueue(db, networkService) {
|
||||
const queue = new JobQueue();
|
||||
try {
|
||||
queue.db = db;
|
||||
queue.networkService = new NetworkService(db);
|
||||
queue.networkService = networkService;
|
||||
const monitors = await db.getAllMonitors();
|
||||
for (const monitor of monitors) {
|
||||
await queue.addJob(monitor.id, monitor);
|
||||
|
||||
@@ -3,8 +3,9 @@ const ping = require("ping");
|
||||
const logger = require("../utils/logger");
|
||||
|
||||
class NetworkService {
|
||||
constructor(db) {
|
||||
constructor(db, emailService) {
|
||||
this.db = db;
|
||||
this.emailService = emailService;
|
||||
this.TYPE_PING = "ping";
|
||||
this.TYPE_HTTP = "http";
|
||||
this.TYPE_PAGESPEED = "pagespeed";
|
||||
@@ -12,6 +13,33 @@ class NetworkService {
|
||||
this.NETWORK_ERROR = 5000;
|
||||
}
|
||||
|
||||
async handleNotification(job, isAlive) {
|
||||
const { _id } = job.data;
|
||||
const monitor = await this.db.getMonitorById(_id);
|
||||
|
||||
// If monitor status changes, update monitor status and send notification
|
||||
if (monitor.status !== isAlive) {
|
||||
monitor.status = !monitor.status;
|
||||
await monitor.save();
|
||||
|
||||
let template =
|
||||
isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate";
|
||||
let status = isAlive === true ? "up" : "down";
|
||||
|
||||
const notifications = await this.db.getNotificationsByMonitorId(_id);
|
||||
for (const notification of notifications) {
|
||||
if (notification.type === "email") {
|
||||
await this.emailService.buildAndSendEmail(
|
||||
template,
|
||||
{ monitorName: monitor.name, monitorUrl: monitor.url },
|
||||
notification.address,
|
||||
`Monitor ${monitor.name} is ${status}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the response time of an asynchronous operation.
|
||||
* @param {Function} operation - An asynchronous operation to measure.
|
||||
@@ -42,10 +70,12 @@ class NetworkService {
|
||||
return response;
|
||||
};
|
||||
|
||||
let isAlive;
|
||||
|
||||
try {
|
||||
const { responseTime, response } =
|
||||
await this.measureResponseTime(operation);
|
||||
const isAlive = response.alive;
|
||||
isAlive = response.alive;
|
||||
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
@@ -54,12 +84,15 @@ class NetworkService {
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} catch (error) {
|
||||
isAlive = false;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: false,
|
||||
status: isAlive,
|
||||
responseTime: error.responseTime,
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} finally {
|
||||
this.handleNotification(job, isAlive);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,13 +108,15 @@ class NetworkService {
|
||||
return response;
|
||||
};
|
||||
|
||||
let isAlive;
|
||||
|
||||
// attempt connection
|
||||
try {
|
||||
const { responseTime, response } =
|
||||
await this.measureResponseTime(operation);
|
||||
|
||||
// check if response is in the 200 range, if so, service is up
|
||||
const isAlive = response.status >= 200 && response.status < 300;
|
||||
isAlive = response.status >= 200 && response.status < 300;
|
||||
|
||||
//Create a check with relevant data
|
||||
const checkData = {
|
||||
@@ -92,9 +127,10 @@ class NetworkService {
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} catch (error) {
|
||||
isAlive = false;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: false,
|
||||
status: isAlive,
|
||||
responseTime: error.responseTime,
|
||||
};
|
||||
// The server returned a response
|
||||
@@ -104,6 +140,8 @@ class NetworkService {
|
||||
checkData.statusCode = this.NETWORK_ERROR;
|
||||
}
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} finally {
|
||||
this.handleNotification(job, isAlive);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +160,8 @@ class NetworkService {
|
||||
* @throws {Error} Throws an error if there is an issue with fetching or processing the PageSpeed insights.
|
||||
*/
|
||||
async handlePagespeed(job) {
|
||||
let isAlive;
|
||||
|
||||
try {
|
||||
const url = job.data.url;
|
||||
const response = await axios.get(
|
||||
@@ -145,9 +185,10 @@ class NetworkService {
|
||||
// Total Blocking Time 30%
|
||||
// Cumulative Layout Shift 25%
|
||||
|
||||
isAlive = true;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: true,
|
||||
status: isAlive,
|
||||
accessibility: (categories.accessibility?.score || 0) * 100,
|
||||
bestPractices: (categories["best-practices"]?.score || 0) * 100,
|
||||
seo: (categories.seo?.score || 0) * 100,
|
||||
@@ -163,15 +204,18 @@ class NetworkService {
|
||||
|
||||
this.logAndStoreCheck(checkData, this.db.createPageSpeedCheck);
|
||||
} catch (error) {
|
||||
isAlive = false;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: false,
|
||||
status: isAlive,
|
||||
accessibility: 0,
|
||||
bestPractices: 0,
|
||||
seo: 0,
|
||||
performance: 0,
|
||||
};
|
||||
this.logAndStoreCheck(checkData, this.db.createPageSpeedCheck);
|
||||
} finally {
|
||||
this.handleNotification(job, isAlive);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user