105 lines
4.0 KiB
TypeScript
105 lines
4.0 KiB
TypeScript
import { Monitor } from "@/domain/monitors/monitor.type.js";
|
|
import { Check } from "@/domain/checks/check.type.js";
|
|
import { DockerStatusPayload, MonitorStatusResponse } from "@/types/network.js";
|
|
import { AppError } from "@/utils/AppError.js";
|
|
import { ILogger } from "@/utils/logger.js";
|
|
import { IBufferService } from "@/service/bufferService.js";
|
|
import { INetworkService } from "@/service/networkService.js";
|
|
import { ICheckService } from "@/domain/checks/check.service.js";
|
|
import { IMonitorsRepository } from "@/domain/monitors/monitor.repository.interface.js";
|
|
import { IMaintenanceWindowsRepository } from "@/domain/maintenance-windows/maintenance-window.repository.interface.js";
|
|
import { isWindowActive } from "@/utils/maintenanceWindow.js";
|
|
import { IProxyResolver } from "@/service/network/ProxyResolver.js";
|
|
import { IDockerLogsService } from "@/domain/docker/docker-log.service.js";
|
|
|
|
export interface ICheckProducer {
|
|
produce(monitor: Monitor): Promise<{ status: MonitorStatusResponse; check: Check } | null>;
|
|
}
|
|
|
|
const SERVICE_NAME = "CheckProducer";
|
|
|
|
export class CheckProducer implements ICheckProducer {
|
|
constructor(
|
|
private monitorsRepository: IMonitorsRepository,
|
|
private maintenanceWindowsRepository: IMaintenanceWindowsRepository,
|
|
private checkService: ICheckService,
|
|
private networkService: INetworkService,
|
|
private proxyResolver: IProxyResolver,
|
|
private bufferService: IBufferService,
|
|
private dockerLogsService: IDockerLogsService,
|
|
private logger: ILogger
|
|
) {}
|
|
|
|
private async isInMaintenanceWindow(monitorId: string, teamId: string) {
|
|
const windows = await this.maintenanceWindowsRepository.findByMonitorId(monitorId, teamId);
|
|
const now = new Date();
|
|
return windows.some((w) => isWindowActive(w, now));
|
|
}
|
|
|
|
private async resolveDockerTlsKey(monitor: Monitor): Promise<string | undefined> {
|
|
if (monitor.type !== "docker" || !monitor.dockerTlsKeySet || !monitor.id) return undefined;
|
|
const dockerTlsKey = await this.monitorsRepository.findDockerTlsKeyById(monitor.id);
|
|
return dockerTlsKey ?? undefined;
|
|
}
|
|
|
|
produce = async (monitor: Monitor) => {
|
|
if (!monitor.id) {
|
|
throw new AppError({ message: "No monitor id", service: SERVICE_NAME, method: "produce" });
|
|
}
|
|
// ****************************
|
|
// Step 1: Acquire
|
|
// ****************************
|
|
|
|
// Step 1a: Maintenance window gate - skip if in maintenance
|
|
const maintenanceWindowActive = await this.isInMaintenanceWindow(monitor.id, monitor.teamId);
|
|
if (maintenanceWindowActive) {
|
|
this.logger.debug({
|
|
message: `Monitor ${monitor.id} is in maintenance window`,
|
|
service: SERVICE_NAME,
|
|
method: "produce",
|
|
});
|
|
if (monitor.status !== "maintenance") {
|
|
// Clear the status window to avoid incidents being created on next check
|
|
await this.monitorsRepository.updateById(monitor.id, monitor.teamId, { status: "maintenance", statusWindow: [] });
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Step 1b: Acquire status
|
|
const proxyUrl = await this.proxyResolver.resolve(monitor);
|
|
const dockerTlsKey = await this.resolveDockerTlsKey(monitor);
|
|
|
|
const status = await this.networkService.requestStatus(monitor, { proxyUrl, dockerTlsKey });
|
|
if (!status) {
|
|
throw new Error("No network response");
|
|
}
|
|
|
|
// ****************************
|
|
// Step 2: Record
|
|
// ****************************
|
|
|
|
// Step 2a: Create & record a check, return null if fail
|
|
const check = this.checkService.toCheck(status);
|
|
if (!check) {
|
|
this.logger.warn({
|
|
message: `No check could be built for monitor ${monitor.id}`,
|
|
service: SERVICE_NAME,
|
|
method: "produce",
|
|
details: { code: status.code, message: status.message },
|
|
});
|
|
return null;
|
|
}
|
|
// Step 2b: Add to buffer
|
|
this.bufferService.addToBuffer(check);
|
|
|
|
// Step 2c: Handle docker logs
|
|
if (status.type === "docker") {
|
|
const dockerLogs = await this.dockerLogsService.buildDockerLogs(status as MonitorStatusResponse<DockerStatusPayload>);
|
|
for (const dockerLog of dockerLogs) {
|
|
this.bufferService.addDockerLogToBuffer(dockerLog);
|
|
}
|
|
}
|
|
return { status, check };
|
|
};
|
|
}
|