/** The slice of `ctx.storage` the alarm lifecycle needs, so tests can pass a fake. */ export interface AlarmStorage { getAlarm(): Promise; setAlarm(scheduledTime: number): Promise; } export const INGEST_INTERVAL_MS = 60_000; /** Arms the first alarm when none is set. The DO calls this from its constructor, so the * first request that wakes the object starts the recurring ingestion. */ export async function ensureAlarm(storage: AlarmStorage, now: number): Promise { if ((await storage.getAlarm()) === null) await storage.setAlarm(now); } /** Runs one pass and always re-arms. A throw is logged, not rethrown: Cloudflare's own retry * gives up after six attempts, which would stop ingestion for good, while the next scheduled * pass retries the same work a minute later. */ export async function runAndRearm(storage: AlarmStorage, run: () => Promise, now: () => number): Promise { try { await run(); } catch (error) { console.error('ingest pass failed', error); } finally { await storage.setAlarm(now() + INGEST_INTERVAL_MS); } }