Skip to content

Recover from poisoned org DB client mutex - #50

Merged
sagnik11 merged 1 commit into
mainfrom
posthog-self-driving/fixorg-db-recover-from-poisoned-client-346697
Aug 17, 2026
Merged

Recover from poisoned org DB client mutex#50
sagnik11 merged 1 commit into
mainfrom
posthog-self-driving/fixorg-db-recover-from-poisoned-client-346697

Conversation

@posthog

@posthog posthog Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Problem

  • Attribution and metrics uploads silently stop for a machine until the daemon restarts, and the only signal is a panic line on stderr.
  • run() in src/api/org_db.rs locked the cached Postgres client with .lock().expect("org client mutex poisoned"). If the wrapped op panics mid-query, Rust marks the mutex poisoned for the life of the process.
  • The client lives in a process-global CONNECTIONS map inside a long-lived daemon, so there is no recovery: every later call panics on the same line.
  • One poisoned mutex takes down all five org DB write paths at once — metrics, notes, CAS, file change counts, and commit authorship summaries.
  • The original panic that poisoned the mutex was swallowed by the telemetry worker's join handle, which reported only a generic "telemetry flush task panicked".

Changes

  • Recover instead of panic. org_db.rs was the lone outlier; the rest of the repo already recovers with unwrap_or_else(|poisoned| poisoned.into_inner()) (about twenty sites in src/streams/db.rs and src/daemon.rs). Apply the same to all five lock sites.
  • Treat a poisoned client mutex like a stale connection. A mid-query panic can leave the Postgres protocol state desynchronized, so reusing that socket would just fail differently. run() now drops the entry from CONNECTIONS and redials — the same recovery it already runs for a dropped connection.
  • Report the hidden panic. Wrap the telemetry flush closure in catch_unwind so a panic logs its own message instead of the join handle's generic text.

Notes

  • No Rust toolchain is available in this environment, so task build, task test, task lint, and task fmt were not run here. The change reuses a pattern already established across the repo; please let CI run the suite.
  • Added a unit test for the new panic_message helper.

Why

The daemon caches the org DB client for its whole life, so a single mid-query panic poisons the mutex permanently and quietly stops the attribution data this product exists to produce. The fix makes the failure recoverable rather than self-sustaining.


Created with PostHog Desktop from this inbox report.

A single op that panicked mid-query while holding the cached Postgres
client guard poisoned the mutex for the life of the daemon process. Every
later org DB write then panicked on the same lock, so metrics, notes, CAS,
file change counts, and commit authorship summaries all stopped syncing
with no signal beyond a stderr panic line.

org_db.rs was the only place that used `.lock().expect(...)`; the rest of
the repo already recovers with `unwrap_or_else(|p| p.into_inner())`. Apply
the same recovery to all five lock sites. For the client mutex, treat a
poisoned lock like the stale-connection case `run()` already handles: drop
the entry from CONNECTIONS and redial, because a mid-query panic can leave
the Postgres protocol state desynchronized.

Also wrap the telemetry flush closure in catch_unwind so a panic reports
its own message instead of being hidden behind the join handle's generic
"task panicked".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: a64999a3-c9e3-4fa2-82bf-cebd47dcc615
@sagnik11
sagnik11 marked this pull request as ready for review August 17, 2026 05:29
@sagnik11
sagnik11 merged commit c239df8 into main Aug 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant