fix(queue): mark superseded webhook_events rows instead of leaving them stuck at 'queued' forever - #3843
Conversation
…em stuck at 'queued' forever (#3814) Both self-host queue backends coalesce a new message into an existing pending row sharing the same job_key by overwriting its payload. The overwritten row's original deliveryId -- and the webhook_events row that delivery already wrote as 'queued' before it ever reached this coalesce -- was discarded with nothing ever marking it processed, error, or otherwise explained. An operator grepping webhook_events for stuck 'queued' rows found real entries with no way to tell "silently coalesced away" from "actually lost." Before overwriting, both pg-queue.ts and sqlite-queue.ts (which mirror each other's coalescing logic exactly and share the identical bug) now read the superseded row's old payload and, when it was itself a github-webhook delivery, mark its webhook_events row 'superseded'. Best-effort and fail-safe: a write hiccup here is logged and swallowed, never allowed to abort the coalesce/enqueue itself.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-06 20:53:51 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 7 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3843 +/- ##
=======================================
Coverage 93.41% 93.42%
=======================================
Files 326 326
Lines 32887 32896 +9
Branches 12044 12046 +2
=======================================
+ Hits 30723 30732 +9
Misses 1530 1530
Partials 634 634
🚀 New features to boost your workflow:
|
Summary
pg-queue.ts/sqlite-queue.ts's generaljob_keycoalesce path (used for e.g. apull_request"opened"/"synchronize" pr-refresh delivery, keyedgithub-webhook:pr-refresh:{repo}#{pr}@{headSha}) finds an existing pending row sharing the same key and overwrites its payload with the new message. The overwritten row's originaldeliveryId— and thewebhook_eventsrow that delivery already wrote asstatus='queued'before it ever reached this coalesce — is discarded with nothing ever marking itprocessed,error, or otherwise explained. An operator greppingwebhook_eventsfor stuckqueuedrows finds real entries with no way to tell "silently coalesced away, handled by a later delivery" from "actually lost."github-webhookdelivery (skipped for every other job type, e.g.rag-index-repo/refresh-registry, which never have awebhook_eventsrow), issue anUPDATE webhook_events SET status='superseded' WHERE delivery_id=... AND status='queued'. Best-effort and fail-safe: a write hiccup here is logged and swallowed, never allowed to abort the coalesce/enqueue itself (the same class of "one failure shouldn't break everything else" bug this whole audit exists to close).webhook_events.statustype insrc/db/repositories.ts(recordWebhookEvent) to include"superseded"for documentation completeness, even though the two queue backends write this status directly via raw SQL (they have no access to the D1/Drizzle layerrecordWebhookEventuses — they operate on the same physical Postgres/SQLite database through their own raw connection).sqlite-queue.ts(self-host's other queue backend), which mirrorspg-queue.ts's coalescing logic exactly and has the identical bug — the issue's own deliverables named onlypg-queue.ts, but fixing one backend and leaving the other with the same defect would be incomplete.Closes #3814.
Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate. (src/selfhost/pg-queue.tsis codecov-exempt percodecov.yml, integration/smoke-tested instead;src/selfhost/sqlite-queue.tsis fully covered — 100% on every new line and branch.)npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateSafety
UI Evidencesection below. (N/A — no visible UI change.)