import { ConvexError, v } from "convex/values" import { query } from "./_generated/server" import { getOfflineThresholdMs, getStaleThresholdMs } from "./machines" const MACHINE_SCAN_LIMIT = 1200 export const healthSnapshot = query({ args: { token: v.optional(v.string()), }, handler: async (ctx, args) => { const requiredToken = process.env["INTERNAL_HEALTH_TOKEN"] ?? process.env["REPORTS_CRON_SECRET"] ?? null if (requiredToken && args.token !== requiredToken) { throw new ConvexError("Nao autorizado") } const now = Date.now() const offlineMs = getOfflineThresholdMs() const staleMs = getStaleThresholdMs(offlineMs) const machines = await ctx.db.query("machines").take(MACHINE_SCAN_LIMIT) const heartbeats = await ctx.db.query("machineHeartbeats").collect() let online = 0 let warning = 0 let offline = 0 let newest = 0 let oldest = 0 const withHeartbeat = new Set() for (const hb of heartbeats) { const ageMs = now - hb.lastHeartbeatAt withHeartbeat.add(String(hb.machineId)) if (newest === 0 || hb.lastHeartbeatAt > newest) { newest = hb.lastHeartbeatAt } if (oldest === 0 || hb.lastHeartbeatAt < oldest) { oldest = hb.lastHeartbeatAt } if (ageMs <= offlineMs) { online += 1 } else if (ageMs <= staleMs) { warning += 1 } else { offline += 1 } } const withoutHeartbeat = machines.length - withHeartbeat.size const totalOffline = offline + (withoutHeartbeat > 0 ? withoutHeartbeat : 0) return { totals: { machines: machines.length, heartbeats: heartbeats.length, withoutHeartbeat: withoutHeartbeat > 0 ? withoutHeartbeat : 0, truncated: machines.length === MACHINE_SCAN_LIMIT, }, connectivity: { online, warning, offline: totalOffline, }, heartbeatAgeMs: { newest: newest ? now - newest : null, oldest: oldest ? now - oldest : null, }, thresholds: { offlineMs, staleMs, }, generatedAt: now, } }, })