notificaitons

This commit is contained in:
Alex Holliday committed 2026-01-05 04:35:01 +00:00
1 parent 3182141d0a
commit e62e4898b9
8 files changed
+39 -45

No files matched your search

+14 -10
View File
@@ -11,6 +11,7 @@ import mongoose from "mongoose";
import { getChildLogger } from "@/logger/Logger.js";
import { ThresholdEvaluationResult } from "@/services/infrastructure/StatusService.js";
import { getStartDate } from "@/utils/TimeUtils.js";
import type { Monitor as MonitorEntity } from "@/types/domain/monitor.js";
type IncidentPopulated = Omit<IIncident, "monitorId" | "resolvedBy"> & {
monitorId: IMonitor;
@@ -19,11 +20,11 @@ type IncidentPopulated = Omit<IIncident, "monitorId" | "resolvedBy"> & {
export interface IIncidentService {
handleStatusChange: (
updatedMonitor: IMonitor,
updatedMonitor: MonitorEntity,
lastCheck: ICheck
) => Promise<IIncident | null>;
handleThresholdBreach: (
updatedMonitor: IMonitor,
updatedMonitor: MonitorEntity,
lastCheck: ICheck,
evalResult: ThresholdEvaluationResult
) => Promise<IIncident | null>;
@@ -66,17 +67,20 @@ class IncidentService implements IIncidentService {
this.SERVICE_NAME = SERVICE_NAME;
}
handleStatusChange = async (updatedMonitor: IMonitor, lastCheck: ICheck) => {
handleStatusChange = async (
updatedMonitor: MonitorEntity,
lastCheck: ICheck
) => {
if (updatedMonitor.status === "down") {
const incident = await this.create(
updatedMonitor.teamId,
updatedMonitor._id,
new mongoose.Types.ObjectId(updatedMonitor.teamId),
new mongoose.Types.ObjectId(updatedMonitor.id),
lastCheck._id
);
return incident;
} else if (updatedMonitor.status === "up") {
const incident = await Incident.findOne({
monitorId: updatedMonitor._id,
monitorId: updatedMonitor.id,
teamId: updatedMonitor.teamId,
resolved: false,
});
@@ -97,12 +101,12 @@ class IncidentService implements IIncidentService {
};
handleThresholdBreach = async (
updatedMonitor: IMonitor,
updatedMonitor: MonitorEntity,
lastCheck: ICheck,
evalResult: ThresholdEvaluationResult
) => {
const existing = await Incident.findOne({
monitorId: updatedMonitor._id,
monitorId: updatedMonitor.id,
teamId: updatedMonitor.teamId,
resolved: false,
});
@@ -110,8 +114,8 @@ class IncidentService implements IIncidentService {
if (evalResult.hasBreach) {
if (!existing) {
const incident = await this.create(
updatedMonitor.teamId,
updatedMonitor._id,
new mongoose.Types.ObjectId(updatedMonitor.teamId),
new mongoose.Types.ObjectId(updatedMonitor.id),
lastCheck._id
);
if (evalResult.notes.length) {
@@ -16,6 +16,7 @@ import SettingsService from "@/services/system/SettingsService.js";
import ApiError from "@/utils/ApiError.js";
import { getChildLogger } from "@/logger/Logger.js";
import type { IEmailTransport } from "./NotificationServices/Email.js";
import type { Monitor as MonitorEntity } from "@/types/domain/index.js";
const SERVICE_NAME = "NotificationService";
const logger = getChildLogger(SERVICE_NAME);
@@ -28,7 +29,7 @@ export interface ITestResult {
}
export interface INotificationService {
handleNotifications: (
monitor: IMonitor,
monitor: MonitorEntity,
incident: IIncident
) => Promise<void>;
testNotificationChannels: (
@@ -58,7 +59,7 @@ class NotificationService implements INotificationService {
this.webhookService = new WebhookService();
}
handleNotifications = async (monitor: IMonitor, incident: IIncident) => {
handleNotifications = async (monitor: MonitorEntity, incident: IIncident) => {
const notificationIds = monitor.notificationChannels || [];
if (notificationIds.length === 0) {
@@ -88,7 +89,7 @@ class NotificationService implements INotificationService {
private sendForChannel = async (
channel: INotificationChannel,
monitor: IMonitor,
monitor: MonitorEntity,
incident: IIncident
): Promise<boolean> => {
try {
@@ -1,8 +1,5 @@
import {
IMonitor,
INotificationChannel,
IIncident,
} from "@/db/models/index.js";
import { INotificationChannel, IIncident } from "@/db/models/index.js";
import type { Monitor } from "@/types/domain/index.js";
import { IAlert, IMessageService } from "./IMessageService.js";
import got from "got";
import ApiError from "@/utils/ApiError.js";
@@ -52,7 +49,7 @@ class DiscordService implements IMessageService {
};
};
buildAlert = (monitor: IMonitor, incident: IIncident) => {
buildAlert = (monitor: Monitor, incident: IIncident) => {
const name = monitor?.name || "Unnamed monitor";
const monitorStatus = monitor?.status || "unknown status";
const url = monitor?.url || "no URL";
@@ -1,8 +1,6 @@
import {
IMonitor,
INotificationChannel,
IIncident,
} from "@/db/models/index.js";
import { INotificationChannel, IIncident } from "@/db/models/index.js";
import type { Monitor } from "@/types/domain/index.js";
import { IMessageService, IAlert } from "./IMessageService.js";
import nodemailer, { Transporter } from "nodemailer";
import { config } from "@/config/index.js";
@@ -123,7 +121,7 @@ class EmailService implements IEmailService {
}
};
buildAlert = (monitor: IMonitor, incident: IIncident) => {
buildAlert = (monitor: Monitor, incident: IIncident) => {
const name = monitor?.name || "Unnamed monitor";
const monitorStatus = monitor?.status || "unknown status";
const url = monitor?.url || "no URL";
@@ -1,9 +1,9 @@
import {
IMonitor,
INotificationChannel,
IIncident,
ResolutionType,
} from "@/db/models/index.js";
import type { Monitor } from "@/types/domain/index.js";
export interface IAlert {
name: string;
@@ -18,7 +18,7 @@ export interface IAlert {
alertTime: Date;
}
export interface IMessageService {
buildAlert: (monitor: IMonitor, incident: IIncident) => IAlert;
buildAlert: (monitor: Monitor, incident: IIncident) => IAlert;
sendMessage: (
alert: IAlert,
channel: INotificationChannel
@@ -1,10 +1,7 @@
import {
IMonitor,
INotificationChannel,
IIncident,
} from "@/db/models/index.js";
import { INotificationChannel, IIncident } from "@/db/models/index.js";
import { IAlert, IMessageService } from "./IMessageService.js";
import got from "got";
import { Monitor } from "@/types/domain/index.js";
import { getChildLogger } from "@/logger/Logger.js";
const SERVICE_NAME = "SlackService";
@@ -113,7 +110,7 @@ class SlackService implements IMessageService {
];
};
buildAlert = (monitor: IMonitor, incident: IIncident) => {
buildAlert = (monitor: Monitor, incident: IIncident) => {
const name = monitor?.name || "Unnamed monitor";
const monitorStatus = monitor?.status || "unknown status";
const url = monitor?.url || "no URL";
@@ -1,12 +1,9 @@
import {
IMonitor,
INotificationChannel,
IIncident,
} from "@/db/models/index.js";
import { INotificationChannel, IIncident } from "@/db/models/index.js";
import { IAlert, IMessageService } from "./IMessageService.js";
import ApiError from "@/utils/ApiError.js";
import got from "got";
import { getChildLogger } from "@/logger/Logger.js";
import type { Monitor } from "@/types/domain/index.js";
const SERVICE_NAME = "WebhookService";
const logger = getChildLogger(SERVICE_NAME);
@@ -17,7 +14,7 @@ class WebhookService implements IMessageService {
this.SERVICE_NAME = SERVICE_NAME;
}
buildAlert = (monitor: IMonitor, incident: IIncident) => {
buildAlert = (monitor: Monitor, incident: IIncident) => {
const name = monitor?.name || "Unnamed monitor";
const monitorStatus = monitor?.status || "unknown status";
const url = monitor?.url || "no URL";
@@ -49,12 +49,12 @@ export interface IStatusService {
) => number;
updateMonitorStats: (
monitor: IMonitor,
monitor: MonitorEntity,
status: StatusResponse,
statusChanged: boolean
) => Promise<IMonitorStats | null>;
evaluateThresholds: (
monitor: IMonitor,
monitor: MonitorEntity,
check: ICheck
) => Promise<ThresholdEvaluationResult>;
}
@@ -151,14 +151,14 @@ class StatusService implements IStatusService {
};
updateMonitorStats = async (
monitor: IMonitor,
monitor: MonitorEntity,
statusResponse: StatusResponse,
statusChanged: boolean
) => {
let stats = await MonitorStats.findOne({ monitorId: monitor._id });
let stats = await MonitorStats.findOne({ monitorId: monitor.id });
if (!stats) {
stats = await MonitorStats.create({
monitorId: monitor._id,
monitorId: monitor.id,
currentStreakStartedAt: Date.now(),
});
}
@@ -203,7 +203,7 @@ class StatusService implements IStatusService {
};
evaluateThresholds = async (
monitor: IMonitor,
monitor: MonitorEntity,
check: ICheck
): Promise<ThresholdEvaluationResult> => {
try {