diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 0dc47278d..ecb49ab40 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -205,6 +205,7 @@ export const initializeServices = async ({ teamsRepository, monitorStatsRepository, checksRepository, + incidentsRepository, }); const superSimpleQueue = await SuperSimpleQueue.create({ diff --git a/server/src/repositories/checks/MongoChecksRepistory.ts b/server/src/repositories/checks/MongoChecksRepistory.ts index 97a81f565..e89bc1c95 100644 --- a/server/src/repositories/checks/MongoChecksRepistory.ts +++ b/server/src/repositories/checks/MongoChecksRepistory.ts @@ -13,7 +13,7 @@ import type { GotTimings, MonitorType, } from "@/types/index.js"; -import { CheckModel, type CheckDocument } from "@/db/models/index.js"; +import { CheckModel, MonitorModel, type CheckDocument } from "@/db/models/index.js"; import mongoose from "mongoose"; const SERVICE_NAME = "StatusService"; diff --git a/server/src/repositories/incidents/IIncidentsRepository.ts b/server/src/repositories/incidents/IIncidentsRepository.ts index 42948a9ee..c4fcef2ae 100644 --- a/server/src/repositories/incidents/IIncidentsRepository.ts +++ b/server/src/repositories/incidents/IIncidentsRepository.ts @@ -24,5 +24,6 @@ export interface IIncidentsRepository { updateById(incidentId: string, teamId: string, updateData: Partial): Promise; // delete deleteByMonitorId(monitorId: string, teamId: string): Promise; + deleteByMonitorIdsNotIn(monitorIds: string[]): Promise; // other } diff --git a/server/src/repositories/incidents/MongoIncidentRepository.ts b/server/src/repositories/incidents/MongoIncidentRepository.ts index b34af4ba7..93ecac248 100644 --- a/server/src/repositories/incidents/MongoIncidentRepository.ts +++ b/server/src/repositories/incidents/MongoIncidentRepository.ts @@ -281,5 +281,11 @@ class MongoIncidentRepository implements IIncidentsRepository { }); return result.deletedCount || 0; }; + + deleteByMonitorIdsNotIn = async (monitorIds: string[]): Promise => { + const objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id)); + const result = await IncidentModel.deleteMany({ monitorId: { $nin: objectIds } }); + return result.deletedCount ?? 0; + }; } export default MongoIncidentRepository; diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts index 8fd55ff70..1947549c9 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts @@ -97,6 +97,7 @@ class SuperSimpleQueue implements ISuperSimpleQueue { this.scheduler.start(); this.scheduler.addTemplate("monitor-job", this.helper.getMonitorJob()); + this.scheduler.addTemplate("cleanup-orphaned", this.helper.getCleanupOrphanedJob()); const monitors = await this.monitorsRepository.findAll(); if (!monitors) { return true; @@ -108,6 +109,8 @@ class SuperSimpleQueue implements ISuperSimpleQueue { }, randomOffset); } + this.scheduler.addJob({ id: "cleanup-orphaned", template: "cleanup-orphaned", active: true }); + return true; } catch (error) { this.logger.error({ diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 05876cc45..d4035d112 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -10,6 +10,7 @@ import { ITeamsRepository, IMonitorStatsRepository, IChecksRepository, + IIncidentsRepository, } from "@/repositories/index.js"; export interface MonitorActionDecision { @@ -41,6 +42,7 @@ class SuperSimpleQueueHelper { private teamsRepository: ITeamsRepository; private monitorStatsRepository: IMonitorStatsRepository; private checksRepository: IChecksRepository; + private incidentsRepository: IIncidentsRepository; constructor({ logger, @@ -55,6 +57,7 @@ class SuperSimpleQueueHelper { teamsRepository, monitorStatsRepository, checksRepository, + incidentsRepository, }: { logger: any; networkService: INetworkService; @@ -68,6 +71,7 @@ class SuperSimpleQueueHelper { teamsRepository: ITeamsRepository; monitorStatsRepository: IMonitorStatsRepository; checksRepository: IChecksRepository; + incidentsRepository: IIncidentsRepository; }) { this.logger = logger; this.networkService = networkService; @@ -81,6 +85,7 @@ class SuperSimpleQueueHelper { this.teamsRepository = teamsRepository; this.monitorStatsRepository = monitorStatsRepository; this.checksRepository = checksRepository; + this.incidentsRepository = incidentsRepository; } get serviceName() { @@ -226,6 +231,14 @@ class SuperSimpleQueueHelper { } // Remove orphaned incidents + const deletedIncidentsCount = await this.incidentsRepository.deleteByMonitorIdsNotIn(allMonitorIds); + if (deletedIncidentsCount > 0) { + this.logger.info({ + message: `Deleted ${deletedIncidentsCount} orphaned incidents`, + service: SERVICE_NAME, + method: "getCleanupOrphanedJob", + }); + } this.logger.info({ message: "Cleanup of orphaned data completed",