···99import { verify } from '@octokit/webhooks-methods'
1010import { sql } from 'drizzle-orm'
1111import { installation, webhookEvent } from '#server/db/schema'
1212+import { kickWorker } from '#server/utils/kick-worker'
1213import { enqueue } from '#server/utils/queue'
1314import { revokeKeysForInstallation } from '#server/utils/tangled-pubkey'
1415···110111 // the raw webhook body. See PLAN.md "Deferred / follow-ups".
111112 if (RECOGNISED_EVENTS.has(eventName)) {
112113 await enqueueForEvent(event, eventName, deliveryId)
114114+ // Nudge the worker to drain the just-enqueued job now rather than on the
115115+ // next cron tick. Fire-and-forget via waitUntil; cron is the safety net.
116116+ kickWorker(event)
113117 }
114118115119 return { ok: true, deliveryId }
···11+import type { H3Event } from 'h3'
22+33+/**
44+ * Nudge the job worker to run now, instead of waiting for the next cron tick.
55+ *
66+ * Fire-and-forget: registered via `event.waitUntil` so the serverless function
77+ * stays alive to complete the kick after the response flushes, but the webhook
88+ * never blocks on it. Any failure is swallowed; the per-minute cron is the
99+ * safety net, so a missed kick only costs latency, not correctness. The worker
1010+ * itself is safe to run concurrently with cron (claims are `FOR UPDATE SKIP
1111+ * LOCKED` with a lease), so a kick racing a tick can't double-process a job.
1212+ *
1313+ * Auth uses the same `CRON_SECRET` bearer the worker route already requires.
1414+ */
1515+export function kickWorker(event: H3Event): void {
1616+ const cronSecret = process.env.CRON_SECRET
1717+ const base = useRuntimeConfig().public.url?.replace(/\/$/, '')
1818+ if (!cronSecret || !base) return
1919+2020+ const run = globalThis.fetch(`${base}/api/jobs/run`, {
2121+ method: 'GET',
2222+ headers: { authorization: `Bearer ${cronSecret}` },
2323+ })
2424+ .then(() => undefined)
2525+ .catch(() => undefined)
2626+2727+ event.waitUntil(run)
2828+}