- pure rollup accumulators with tests; daily upserts keyed date/metric/dim - alert checks with db-backed cooldown and push to admin players - in-process scheduler started from health probes - health endpoint checks pb + supertokens, stale-while-revalidate, always 200 - sse connection counter moved to emitter - telemetry feature server fns: events/errors/groups/rollups/alerts/status
57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
export interface HealthChecks {
|
|
pocketbase: "ok" | "down";
|
|
supertokens: "ok" | "down";
|
|
}
|
|
|
|
export interface HealthSnapshot {
|
|
status: "ok" | "degraded";
|
|
checks: HealthChecks;
|
|
checkedAt: string;
|
|
}
|
|
|
|
const CHECK_TTL_MS = 10_000;
|
|
const CHECK_TIMEOUT_MS = 2_000;
|
|
|
|
let cached: HealthSnapshot | null = null;
|
|
let refreshing: Promise<HealthSnapshot> | null = null;
|
|
|
|
const ping = async (url: string): Promise<boolean> => {
|
|
try {
|
|
const response = await fetch(url, { signal: AbortSignal.timeout(CHECK_TIMEOUT_MS) });
|
|
return response.ok;
|
|
} catch {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const runChecks = async (): Promise<HealthSnapshot> => {
|
|
const [pocketbase, supertokens] = await Promise.all([
|
|
ping(`${process.env.POCKETBASE_URL}/api/health`),
|
|
ping(`${process.env.SUPERTOKENS_URI}/hello`),
|
|
]);
|
|
|
|
cached = {
|
|
status: pocketbase && supertokens ? "ok" : "degraded",
|
|
checks: {
|
|
pocketbase: pocketbase ? "ok" : "down",
|
|
supertokens: supertokens ? "ok" : "down",
|
|
},
|
|
checkedAt: new Date().toISOString(),
|
|
};
|
|
return cached;
|
|
};
|
|
|
|
// Stale-while-revalidate: k8s probes get the cached snapshot instantly while a
|
|
// refresh runs in the background; only the very first request awaits a check.
|
|
export const getHealthSnapshot = async (): Promise<HealthSnapshot> => {
|
|
if (cached && Date.now() - Date.parse(cached.checkedAt) < CHECK_TTL_MS) {
|
|
return cached;
|
|
}
|
|
if (!refreshing) {
|
|
refreshing = runChecks().finally(() => {
|
|
refreshing = null;
|
|
});
|
|
}
|
|
return cached ?? refreshing;
|
|
};
|