You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(runtime): bound the shutdown drain, serialize boot migrations, and make capture failures visible (#9485, #9486, #9487)
stop() waited on in-flight work with NO deadline, so a redeploy blocked on a multi-minute AI
review until the orchestrator SIGKILLed the process -- and because the killed job's lease had
been heartbeated right up to the kill, reclaimExpiredProcessingJobs (which only recovers rows
older than 30 minutes) left it stalled for another 20-30. Against a 1-5 minute latency target
with automated redeploys, that was the largest single source of a silently stalled review. The
wait is now bounded, and on expiry this process re-pends its OWN in-flight rows -- safe because
activeJobIds is process-local -- turning a SIGKILL race into an immediate retry. Both backends.
Boot migrations took no cross-instance lock. Two instances booting together meant one applied a
migration atomically while the other's identical transaction failed "already exists", which
runSelfHostMigrations treats as DRIFT and retries statement-by-statement -- re-executing any
table-rebuild INSERT ... SELECT or UPDATE backfill against the already-migrated schema, then
dying on the ledger INSERT's unique violation (a message matching neither tolerated shape) and
crash-looping. #9027 made a single migration atomic against a crash; this makes the whole run
atomic against a concurrent boot, via a Postgres session advisory lock. A session lock is held
by its connection, so it cannot be taken through the pooled adapter -- hence the adapter->pool
registry rather than a new statement.
Visual capture failures were logged but never counted, so a browserless outage was invisible in
Prometheus while it degraded every screenshot to a dash cell -- and since the screenshot gate
treats absent evidence as a close signal, that outage could close legitimate visual PRs before
anyone noticed.
["loopover_config_dir_empty_acknowledged",{help: "1 when LOOPOVER_REPO_CONFIG_DIR is unset, has entries, or is acknowledged; 0 when it's configured but the mounted directory is empty.",type: "gauge"}],
59
59
["loopover_http_requests_total",{help: "HTTP app requests by response status class.",type: "counter"}],
60
60
["loopover_http_request_duration_seconds",{help: "HTTP app request duration in seconds.",type: "histogram"}],
61
+
["loopover_visual_capture_total",{help: "Visual capture attempts by result -- a browserless outage is otherwise invisible while it silently degrades screenshots to dash cells, and the screenshot gate treats absent evidence as a close signal (#9487).",type: "counter"}],
61
62
["loopover_webhook_dedup_total",{help: "Webhook deliveries deduplicated before enqueue.",type: "counter"}],
62
63
["loopover_webhook_enqueue_total",{help: "Webhook enqueue outcomes by event and action.",type: "counter"}],
63
64
["loopover_jobs_enqueued_total",{help: "Durable queue jobs enqueued.",type: "counter"}],
0 commit comments