1,396 bytes · the TypeScript implementation · view raw
import { type HeartbeatStatus } from"./monitor_heartbeat_types.ts";
function whole(name: string, v: number): void {
if (!Number.isSafeInteger(v)) thrownew RangeError(`${name} must be whole seconds, received ${v}`);
}
/** * New, up, late or down, as healthchecks.io names them. Up through the due * second itself, late through the last second of the grace time, down after. * A ping stamped in the future (clock skew between the job and the monitor) * is simply up: its due time is later still. */exportfunction heartbeatStatus(lastPingAt: number | null, now: number, intervalSeconds: number, graceSeconds: number): HeartbeatStatus {
if (lastPingAt !== null) whole("lastPingAt", lastPingAt);
whole("now", now);
whole("intervalSeconds", intervalSeconds);
whole("graceSeconds", graceSeconds);
if (intervalSeconds < 1) thrownew RangeError(`intervalSeconds must be at least 1, received ${intervalSeconds}`);
if (graceSeconds < 0) thrownew RangeError(`graceSeconds must not be negative, received ${graceSeconds}`);
if (lastPingAt === null) return { state: "new", dueAt: null, downAt: null, overdueSeconds: 0 };
const dueAt = lastPingAt + intervalSeconds;
const downAt = dueAt + graceSeconds;
if (now <= dueAt) return { state: "up", dueAt, downAt, overdueSeconds: 0 };
return { state: now <= downAt ? "late" : "down", dueAt, downAt, overdueSeconds: now - dueAt };
}