feat: lookahead scheduling — API returns scheduled_at_ms, nodes sleep-until for tight coordination

This commit is contained in:
M1
2026-03-18 17:14:28 +04:00
parent 7b98ae78e5
commit c5eb514990
4 changed files with 40 additions and 24 deletions
+14 -10
View File
@@ -31,18 +31,22 @@ export const internal = new Elysia({ prefix: "/internal", detail: { hide: true }
return {};
})
// Returns monitors that are due for a check.
// When a region is provided, due-ness and scheduled_at are based on
// the last ping from that specific region — so each region has its own
// independent schedule and they don't drift against each other.
// Returns monitors due within the next `lookahead_ms` milliseconds (default 2000).
// Nodes receive scheduled_at as an exact unix ms timestamp and sleep until that
// moment before firing — all regions coordinate to the same scheduled slot.
.get("/due", async ({ request }) => {
const region = new URL(request.url).searchParams.get('region') || undefined;
const params = new URL(request.url).searchParams;
const region = params.get('region') || undefined;
const lookaheadMs = Math.min(Number(params.get('lookahead_ms') || 2000), 10000);
const monitors = await sql`
SELECT m.id, m.url, m.method, m.request_headers, m.request_body, m.timeout_ms, m.interval_s, m.query, m.regions,
CASE
WHEN last.checked_at IS NULL THEN now()
ELSE last.checked_at + (m.interval_s || ' seconds')::interval
END AS scheduled_at
EXTRACT(EPOCH FROM (
CASE
WHEN last.checked_at IS NULL THEN now()
ELSE last.checked_at + (m.interval_s || ' seconds')::interval
END
))::bigint * 1000 AS scheduled_at_ms
FROM monitors m
LEFT JOIN LATERAL (
SELECT checked_at FROM pings
@@ -52,7 +56,7 @@ export const internal = new Elysia({ prefix: "/internal", detail: { hide: true }
) last ON true
WHERE m.enabled = true
AND (last.checked_at IS NULL
OR last.checked_at < now() - (m.interval_s || ' seconds')::interval)
OR last.checked_at < now() - (m.interval_s || ' seconds')::interval + (${lookaheadMs} || ' milliseconds')::interval)
AND (
array_length(m.regions, 1) IS NULL
OR m.regions = '{}'