Public: anyone can read this; the crew can change it.
Two processes at once: each run queued once, each webhook sent once, streams drained with a resume hint #909
Check · Review · Land · Live done — Landed and live in production.
Closes #875 together with #902 (part a, additive migrations). This is part b: two processes on one data dir.
shipped production is serving it for issue #875 — its issue is already done deploy fc82d1a
Sign in to join this conversation.
new above
offline
Closes #875 together with #902 (part a, additive migrations). This is part b: two processes on one data dir.
Shared functions that change:
queueAgentRun(crew/dispatch.ts): its look and its insert are now one write transaction.request: the same.deliverDue(core/webhooks.ts): it claims each delivery before sending it.eventStream(http/sse.ts): it registers every open stream, and the newdrainStreams()ends them all.What changed
test/overlap.test.tsshows it with two real processes racing to queue the crew on 400 issues: before this change, issues got two runs each. The crew's queueing and the checks' queueing now happen insidetransact(BEGIN IMMEDIATE), so each issue ends with exactly one run.deliverDuenow claims a row with a 60-second lease onnext_try_atbefore sending it. Only the claimant sends; a sender that dies mid-send is retried when the lease runs out.retry: 1000andevent: drain, so browsers reconnect, to the new process, from the last id they saw. They no longer hold the old socket until it exits.main.ts'sshutdowncallsdrainStreams()first.claimRun,queueAgentRun, the checks'request, run leases, webhook claims,claimPromptRunand the reconciler.Tests (
test/overlap.test.ts, in the gate; each failed before its change):/eventsstream with the resume hint.Not here: a minute-long soak with two full forges is the rehearsal on a copy (#873, part 4). This test holds each shared write path instead. App environments stay per-process by design, and the section says so.
🤖 Generated with Claude Code