Files
Checkmate/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts
T

139 lines
4.0 KiB
TypeScript
Raw Normal View History

2025-07-25 15:15:14 -07:00
const SERVICE_NAME = "JobQueueHelper";
2026-01-15 22:06:46 +00:00
import type { Monitor } from "@/types/monitor.js";
import { AppError } from "@/utils/AppError.js";
2026-01-18 23:38:40 +00:00
import { INetworkService, INotificationsService, IStatusService } from "@/service/index.js";
2025-06-27 12:38:06 +08:00
class SuperSimpleQueueHelper {
2025-07-25 15:15:14 -07:00
static SERVICE_NAME = SERVICE_NAME;
2025-08-18 10:55:12 -07:00
2026-01-15 22:06:46 +00:00
private db: any;
private logger: any;
2026-01-15 23:45:40 +00:00
private networkService: INetworkService;
2026-01-18 23:38:40 +00:00
private statusService: IStatusService;
2026-01-18 22:52:59 +00:00
private notificationsService: INotificationsService;
2026-01-16 18:11:04 +00:00
private checkService: any;
private buffer: any;
2026-01-15 22:06:46 +00:00
constructor({
db,
logger,
networkService,
statusService,
2026-01-18 22:52:59 +00:00
notificationsService,
2026-01-16 18:11:04 +00:00
checkService,
buffer,
2026-01-15 22:06:46 +00:00
}: {
db: any;
logger: any;
2026-01-15 23:45:40 +00:00
networkService: INetworkService;
2026-01-18 23:38:40 +00:00
statusService: IStatusService;
2026-01-18 22:52:59 +00:00
notificationsService: INotificationsService;
2026-01-16 18:11:04 +00:00
checkService: any;
buffer: any;
2026-01-15 22:06:46 +00:00
}) {
2025-06-27 12:38:06 +08:00
this.db = db;
this.logger = logger;
this.networkService = networkService;
this.statusService = statusService;
2026-01-16 18:11:04 +00:00
this.checkService = checkService;
this.buffer = buffer;
2026-01-18 22:52:59 +00:00
this.notificationsService = notificationsService;
2025-06-27 12:38:06 +08:00
}
2025-07-25 15:15:14 -07:00
get serviceName() {
return SuperSimpleQueueHelper.SERVICE_NAME;
}
2025-06-27 12:38:06 +08:00
getMonitorJob = () => {
2026-01-15 22:06:46 +00:00
return async (monitor: Monitor) => {
2025-06-27 12:38:06 +08:00
try {
2026-01-13 20:20:00 +00:00
const monitorId = monitor.id;
const teamId = monitor.teamId;
2025-06-27 12:38:06 +08:00
if (!monitorId) {
2026-01-15 22:06:46 +00:00
throw new AppError({ message: "No monitor id", service: SERVICE_NAME, method: "getMonitorJob" });
2025-06-27 12:38:06 +08:00
}
2026-01-15 22:06:46 +00:00
// Step 1. Check for maintenacne window, if found, skip the check
const maintenanceWindowActive = await this.isInMaintenanceWindow(monitorId, teamId);
2025-06-27 12:38:06 +08:00
if (maintenanceWindowActive) {
2026-01-15 22:06:46 +00:00
this.logger.debug({
2025-06-27 12:38:06 +08:00
message: `Monitor ${monitorId} is in maintenance window`,
service: SERVICE_NAME,
method: "getMonitorJob",
});
return;
}
2025-08-15 16:04:43 -07:00
2026-01-15 22:06:46 +00:00
// Step 2. Request monitor status
const status = await this.networkService.requestStatus(monitor);
if (!status) {
2025-06-27 12:38:06 +08:00
throw new Error("No network response");
}
2026-01-16 18:11:04 +00:00
// Step 3. Build check
const check = await this.checkService.buildCheck(status);
// Step 4 Add check to buffer
this.buffer.addToBuffer({ check });
// Step 4. Update monitor status
const statusChangeResult = await this.statusService.updateMonitorStatus(status, check);
2026-01-19 18:58:17 +00:00
// Step 5 handle notifications (best effort, continue even in event of failure, don't wait)
2026-01-19 21:39:02 +00:00
this.notificationsService
.handleNotifications(monitor, status, statusChangeResult.prevStatus, statusChangeResult.statusChanged)
.catch((error: any) => {
this.logger.error({
message: error.message,
service: SERVICE_NAME,
method: "getMonitorJob",
details: `Error sending notifications for job ${monitor.id}: ${error.message}`,
stack: error.stack,
});
});
2026-01-15 22:06:46 +00:00
} catch (error: any) {
2025-06-27 12:38:06 +08:00
this.logger.warn({
message: error.message,
service: error.service || SERVICE_NAME,
method: error.method || "getMonitorJob",
stack: error.stack,
});
throw error;
}
};
};
2026-01-15 22:06:46 +00:00
async isInMaintenanceWindow(monitorId: string, teamId: string) {
const maintenanceWindows = await this.db.maintenanceWindowModule.getMaintenanceWindowsByMonitorId({
2026-01-15 22:06:46 +00:00
monitorId: monitorId,
teamId: teamId,
});
2025-06-27 12:38:06 +08:00
// Check for active maintenance window:
2026-01-15 22:06:46 +00:00
const maintenanceWindowIsActive = maintenanceWindows.reduce((acc: any, window: any) => {
2025-06-27 12:38:06 +08:00
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 SuperSimpleQueueHelper;