This commit is contained in:
nate 2026-04-08 14:45:26 +04:00
parent 1434330545
commit c74ee9856e
3 changed files with 25 additions and 10 deletions

View File

@ -7,6 +7,15 @@ import { channels } from "./routes/channels";
import { migrate } from "./db"; import { migrate } from "./db";
import { SECURITY_HEADERS } from "../../shared/auth"; import { SECURITY_HEADERS } from "../../shared/auth";
// Global safety net: never let an unhandled rejection take down the API process.
// We'd rather log loudly and stay up than 502 every monitor on a single bug.
process.on("unhandledRejection", (reason) => {
console.error("[unhandledRejection]", reason);
});
process.on("uncaughtException", (err) => {
console.error("[uncaughtException]", err);
});
await migrate(); await migrate();
const elysia = new Elysia() const elysia = new Elysia()

View File

@ -26,14 +26,20 @@ export async function dispatch(channel: ChannelRow, event: NotificationEvent): P
} }
export async function dispatchForMonitor(monitorId: string, event: NotificationEvent): Promise<void> { export async function dispatchForMonitor(monitorId: string, event: NotificationEvent): Promise<void> {
const channels = await sql<ChannelRow[]>` // Belt-and-braces: this is called fire-and-forget from the ingest path, so any
SELECT c.id, c.account_id, c.name, c.kind, c.config, c.enabled // error escaping here would become an unhandled rejection and crash the process.
FROM notification_channels c try {
JOIN monitor_notifications mn ON mn.channel_id = c.id const channels = await sql<ChannelRow[]>`
WHERE mn.monitor_id = ${monitorId} AND c.enabled = true SELECT c.id, c.account_id, c.name, c.kind, c.config, c.enabled
`; FROM notification_channels c
if (channels.length === 0) return; JOIN monitor_notifications mn ON mn.channel_id = c.id
await Promise.all(channels.map((c) => dispatch(c, event))); WHERE mn.monitor_id = ${monitorId} AND c.enabled = true
`;
if (channels.length === 0) return;
await Promise.all(channels.map((c) => dispatch(c, event)));
} catch (e) {
console.warn(`[notify] dispatchForMonitor failed for ${monitorId}:`, e);
}
} }
export type { NotificationEvent, ChannelRow, MonitorContext, PingContext } from "./types"; export type { NotificationEvent, ChannelRow, MonitorContext, PingContext } from "./types";

View File

@ -169,11 +169,11 @@ export const ingest = new Elysia()
: { kind: "down", monitor: monitorCtx, ping: pingCtx }; : { kind: "down", monitor: monitorCtx, ping: pingCtx };
// Suppress the synthetic "up" on a brand-new monitor (no prior state). // Suppress the synthetic "up" on a brand-new monitor (no prior state).
if (!(body.up && prevState === null)) { if (!(body.up && prevState === null)) {
void dispatchForMonitor(monitor_check.id, event); dispatchForMonitor(monitor_check.id, event).catch((e) => console.warn("[notify] dispatch escaped:", e));
} }
} }
if (certEvent && days != null) { if (certEvent && days != null) {
void dispatchForMonitor(monitor_check.id, { kind: "cert", monitor: monitorCtx, days }); dispatchForMonitor(monitor_check.id, { kind: "cert", monitor: monitorCtx, days }).catch((e) => console.warn("[notify] cert dispatch escaped:", e));
} }
return { ok: true }; return { ok: true };