diff --git a/apps/web/src/routes/api/cron/+server.ts b/apps/web/src/routes/api/cron/+server.ts index 6308d67..d1bf03a 100644 --- a/apps/web/src/routes/api/cron/+server.ts +++ b/apps/web/src/routes/api/cron/+server.ts @@ -25,7 +25,6 @@ export const POST: RequestHandler = async ({ request, platform }) => { // Firehose ingest — guarded so an over-budget cycle can't 500 the whole tick // (which previously also took the bot down with it). try { - await ensureInit(db, platform!.env); // Two deliberately-split budgets. contrail saves the jetstream cursor LAST in // runIngestCycle — after the drain, applyEvents, and the per-DID // refreshStaleIdentities network tail. If this handler aborts before that @@ -40,16 +39,26 @@ export const POST: RequestHandler = async ({ request, platform }) => { // normal cycle, and under the cron interval so ticks don't overlap. // Scheduled invocations get ~15min wall-clock and this is I/O-bound, // so the tail has ample room. + // The HARD budget covers ARMING too: ensureInit runs INSIDE the race, ahead + // of ingest (the sink must be armed before ingest upserts — see the ordering + // rationale in $lib/contrail/index.ts). ensureInit's own settings fetch is + // separately time-bounded, but that bound would be ADDITIVE to HARD if arming + // were awaited before the race — a stalling search endpoint could then push a + // tick past the cron interval and overlap the next one. Racing arming + + // ingest together keeps the whole tick under HARD, and thus under the interval. const DRAIN_TIMEOUT_MS = 20_000; const HARD_TIMEOUT_MS = 55_000; await Promise.race([ - contrail.ingest({ timeoutMs: DRAIN_TIMEOUT_MS }, db), + (async () => { + await ensureInit(db, platform!.env); + await contrail.ingest({ timeoutMs: DRAIN_TIMEOUT_MS }, db); + })(), new Promise((_, reject) => setTimeout(() => reject(new Error('ingest hard timeout')), HARD_TIMEOUT_MS) ) ]); } catch (e) { - console.error('[cron] contrail.ingest failed:', e); + console.error('[cron] ingest cycle failed:', e); } // atmo.pub notifications: event reminders + host RSVP alerts. Runs after