2,253 bytes · the TypeScript implementation · view raw
import { type Check, type CheckStatus } from"./monitor_check_status_types.ts";
import { type Incident } from"./monitor_incidents_types.ts";
/** * The incidents in a check series. A run of consecutive bad checks is one * incident, from its first bad check to the first good check after it, but * only when it holds at least confirmChecks checks: a single failed probe is * noise, not an outage, and would otherwise page and skew MTTR. */exportfunction findIncidents(checks: readonly Check[], incidentStatus: CheckStatus, confirmChecks: number, now: number): readonly Incident[] {
if (!Number.isSafeInteger(now)) thrownew RangeError("now must be a whole number of seconds");
if (incidentStatus !== "down" && incidentStatus !== "degraded") {
thrownew RangeError(`incidentStatus must be down or degraded, received ${String(incidentStatus)}`);
}
if (!Number.isSafeInteger(confirmChecks) || confirmChecks < 1) {
thrownew RangeError(`confirmChecks must be at least 1, received ${confirmChecks}`);
}
for (let i = 0; i < checks.length; i++) {
const s = checks[i].status;
if (s !== "up" && s !== "degraded" && s !== "down") thrownew RangeError(`unknown check status: ${String(s)}`);
if (i > 0 && checks[i].at <= checks[i - 1].at) {
thrownew RangeError(`checks must be in strictly ascending time order: ${checks[i].at} follows ${checks[i - 1].at}`);
}
}
if (checks.length > 0 && now < checks[checks.length - 1].at) {
thrownew RangeError(`now ${now} is before the last check at ${checks[checks.length - 1].at}`);
}
const bad = (s: CheckStatus): boolean => s === "down" || (incidentStatus === "degraded" && s === "degraded");
const out: Incident[] = [];
let i = 0;
while (i < checks.length) {
if (!bad(checks[i].status)) { i++; continue; }
const start = checks[i].at;
let count = 0;
let worst: CheckStatus = "degraded";
while (i < checks.length && bad(checks[i].status)) {
if (checks[i].status === "down") worst = "down";
count++;
i++;
}
const end = i < checks.length ? checks[i].at : null;
if (count >= confirmChecks) {
out.push({ start, end, durationSeconds: (end ?? now) - start, worst, checks: count });
}
}
return out;
}