From e0ff0a34a78cd248c6abb6621923a63ecc1d4686 Mon Sep 17 00:00:00 2001 From: Trevor Walker Date: Wed, 26 Aug 2026 11:58:12 -0600 Subject: [PATCH] fix(relay): sweep expired state hourly instead of every five minutes The relay's housekeeping cron ran every five minutes, and Neon's Free plan suspends the compute after five idle minutes, so the database never slept: about 180 CU-hours a month at the minimum compute size against a 100 CU-hour allowance. It ran dry on 2026-08-26 and took the relay down. Nothing depends on the sweep's timing: DPoP replay detection is an insert conflict on the proof id, and terminal Live Activity rows stop rendering after TERMINAL_AGENT_ACTIVITY_DISPLAY_TTL_MS regardless of when the row is deleted. Hourly keeps the same tables tidy for roughly 15 CU-hours a month. --- infra/relay/src/worker.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/infra/relay/src/worker.ts b/infra/relay/src/worker.ts index 77dfd845c..ad5fa68b6 100644 --- a/infra/relay/src/worker.ts +++ b/infra/relay/src/worker.ts @@ -260,7 +260,13 @@ export const ApiLive = Api.make( ), ); - yield* Cloudflare.Workers.cron("*/5 * * * *", () => + // Hourly, not every five minutes: Neon's Free plan suspends the compute + // after five idle minutes, so a five-minute sweep kept it awake around the + // clock (~180 CU-hours/month against a 100 CU-hour allowance). Nothing + // reads these rows on a schedule — DPoP replay is an insert conflict and + // terminal Live Activity rows stop rendering after + // TERMINAL_AGENT_ACTIVITY_DISPLAY_TTL_MS — so the sweep only reclaims space. + yield* Cloudflare.Workers.cron("0 * * * *", () => DpopProofs.DpopProofReplay.pipe( Effect.flatMap((dpopProofs) => dpopProofs.pruneExpired), // Terminal thread rows are kept briefly so finished agents show as