my own status page
at main 62 lines 2.1 kB view raw
1import type { Env, Incident, ServicesManifest } from "./types"; 2import { getManifest } from "./manifest"; 3import { getAllLatestPings, getActiveIncidents } from "./db"; 4import { getDeviceStatus } from "./tailscale"; 5 6export type OverallGrade = "up" | "degraded" | "down"; 7 8export interface OverallStatus { 9 grade: OverallGrade; 10 label: string; 11} 12 13export async function getOverallStatus( 14 env: Env, 15 prefetched?: { 16 manifest?: ServicesManifest; 17 latestPings?: Map<string, { status: string; latency_ms: number | null }>; 18 activeIncidents?: Incident[]; 19 machineOnline?: Map<string, boolean>; 20 }, 21): Promise<OverallStatus> { 22 const manifest = prefetched?.manifest ?? await getManifest(env); 23 const latestPings = prefetched?.latestPings ?? await getAllLatestPings(env.DB); 24 const activeIncidents = prefetched?.activeIncidents ?? await getActiveIncidents(env.DB); 25 26 const servers = Object.entries(manifest).filter( 27 ([, m]) => m.type === "server" && m.services.some((s) => s.health_url), 28 ); 29 30 const statuses: string[] = []; 31 let anyServerOffline = false; 32 33 for (const [name, machine] of servers) { 34 const online = prefetched?.machineOnline?.get(name) ?? await getDeviceStatus(env, machine.tailscale_host); 35 if (!online) anyServerOffline = true; 36 37 for (const svc of machine.services.filter((s) => s.health_url)) { 38 const ping = latestPings.get(svc.name); 39 statuses.push(ping?.status ?? "unknown"); 40 } 41 } 42 43 const downCount = statuses.filter( 44 (s) => s === "down" || s === "timeout", 45 ).length; 46 const downRatio = statuses.length > 0 ? downCount / statuses.length : 0; 47 const onFire = anyServerOffline || downRatio >= 0.4; 48 const hasDegraded = statuses.some( 49 (s) => 50 s === "down" || 51 s === "timeout" || 52 s === "degraded" || 53 s === "misconfigured", 54 ); 55 56 const hasCritical = activeIncidents.some((i) => i.severity === "critical"); 57 const hasMajor = activeIncidents.some((i) => i.severity === "major"); 58 59 if (hasCritical || onFire) return { grade: "down", label: "On fire" }; 60 if (hasMajor || hasDegraded) return { grade: "degraded", label: "Some systems degraded" }; 61 return { grade: "up", label: "All systems operational" }; 62}