fix: improve state management
This commit is contained in:
parent
27d8630611
commit
4bf8d1b20d
|
|
@ -29,35 +29,42 @@ export const internal = new Elysia({ prefix: "/internal", detail: { hide: true }
|
||||||
|
|
||||||
.get("/due", async ({ request }) => {
|
.get("/due", async ({ request }) => {
|
||||||
const params = new URL(request.url).searchParams;
|
const params = new URL(request.url).searchParams;
|
||||||
const region = params.get('region') || undefined;
|
const region = params.get('region') || 'default';
|
||||||
const lookaheadMs = Math.min(Number(params.get('lookahead_ms') || 2000), 10000);
|
const lookaheadMs = Math.min(Number(params.get('lookahead_ms') || 2000), 10000);
|
||||||
|
|
||||||
|
// No JOIN, no state lookup. The check schedule for a monitor is purely
|
||||||
|
// a function of its created_at and interval_s — every interval since
|
||||||
|
// creation is a tick. We pull all enabled monitors that match this
|
||||||
|
// region, compute the next tick in JS, and return the ones whose next
|
||||||
|
// tick falls within the lookahead window.
|
||||||
const monitors = await sql`
|
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,
|
SELECT id, url, method, request_headers, request_body, timeout_ms, interval_s, query, regions,
|
||||||
m.max_retries, m.retry_interval_s,
|
max_retries, retry_interval_s, created_at
|
||||||
EXTRACT(EPOCH FROM (
|
FROM monitors
|
||||||
CASE
|
WHERE enabled = true
|
||||||
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
|
|
||||||
WHERE monitor_id = m.id
|
|
||||||
AND (${region ? sql`region = ${region}` : sql`true`})
|
|
||||||
ORDER BY checked_at DESC LIMIT 1
|
|
||||||
) last ON true
|
|
||||||
WHERE m.enabled = true
|
|
||||||
AND (last.checked_at IS NULL
|
|
||||||
OR last.checked_at < now() - (m.interval_s || ' seconds')::interval + (${lookaheadMs} || ' milliseconds')::interval)
|
|
||||||
AND (
|
AND (
|
||||||
array_length(m.regions, 1) IS NULL
|
array_length(regions, 1) IS NULL
|
||||||
OR m.regions = '{}'
|
OR regions = '{}'
|
||||||
OR ${region ? sql`${region} = ANY(m.regions)` : sql`true`}
|
OR ${region} = ANY(regions)
|
||||||
)
|
)
|
||||||
|
LIMIT 500
|
||||||
`;
|
`;
|
||||||
return monitors;
|
|
||||||
|
const nowMs = Date.now();
|
||||||
|
const lookaheadEnd = nowMs + lookaheadMs;
|
||||||
|
const due: any[] = [];
|
||||||
|
for (const m of monitors) {
|
||||||
|
const createdMs = new Date((m as any).created_at).getTime();
|
||||||
|
const intervalMs = Number((m as any).interval_s) * 1000;
|
||||||
|
if (intervalMs <= 0) continue;
|
||||||
|
const elapsed = nowMs - createdMs;
|
||||||
|
const ticksPassed = Math.floor(elapsed / intervalMs);
|
||||||
|
const nextTickMs = createdMs + (ticksPassed + 1) * intervalMs;
|
||||||
|
if (nextTickMs <= lookaheadEnd) {
|
||||||
|
due.push({ ...m, scheduled_at_ms: nextTickMs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return due;
|
||||||
})
|
})
|
||||||
|
|
||||||
.post("/prune", async () => {
|
.post("/prune", async () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue