Recover from mutex poisoning in db_pool
Move the lock() call into db_pool() itself, using unwrap_or_else(|e| e.into_inner()) so a panic in one task cannot cascade into a server-wide crash for all subsequent DB requests. Call sites now receive a MutexGuard directly.
diff --git a/quire-server/src/quire/mod.rs b/quire-server/src/quire/mod.rs
index 8b7ad3b..2333701 100644
--- a/quire-server/src/quire/mod.rs
+++ b/quire-server/src/quire/mod.rs
@@ -270,11 +270,12 @@ impl Quire {
///
/// Lazily initialises the connection on first call. Once open, the
/// same connection is reused for all subsequent requests.
- pub fn db_pool(&self) -> &Mutex<rusqlite::Connection> {
- self.db_pool.get_or_init(|| {
+ pub fn db_pool(&self) -> std::sync::MutexGuard<'_, rusqlite::Connection> {
+ let mutex = self.db_pool.get_or_init(|| {
let conn = crate::db::open(&self.db_path()).expect("failed to open database");
Mutex::new(conn)
- })
+ });
+ mutex.lock().unwrap_or_else(|e| e.into_inner())
}
/// Validate a repository name and return its resolved path.
diff --git a/quire-server/src/quire/web/api.rs b/quire-server/src/quire/web/api.rs
index 2dfca7a..b639ce7 100644
--- a/quire-server/src/quire/web/api.rs
+++ b/quire-server/src/quire/web/api.rs
@@ -113,7 +113,7 @@ async fn verify_run_token(
let token = bearer.token().to_string();
let run_id = tokio::task::spawn_blocking(move || -> Result<String, ApiError> {
- let db = quire.db_pool().lock().expect("db mutex poisoned");
+ let db = quire.db_pool();
let result: rusqlite::Result<String> = db.query_row(
"SELECT id FROM runs WHERE run_token = ?1",
rusqlite::params![token],
diff --git a/quire-server/src/quire/web/db.rs b/quire-server/src/quire/web/db.rs
index 74682fb..8777b93 100644
--- a/quire-server/src/quire/web/db.rs
+++ b/quire-server/src/quire/web/db.rs
@@ -32,10 +32,7 @@ pub struct ShEvent {
}
pub fn load_runs(quire: &Quire, repo: &str) -> Result<Vec<RunRow>> {
- let db = quire
- .db_pool()
- .lock()
- .map_err(|_| crate::error::Error::Io(std::io::Error::other("db mutex poisoned")))?;
+ let db = quire.db_pool();
let mut stmt = db.prepare(
"SELECT id, outcome, sha, ref_name, created_at, dispatched_at, resolved_at
FROM runs WHERE repo = ?1
@@ -68,10 +65,7 @@ pub struct RunDetail {
}
pub fn load_run_detail(quire: &Quire, repo: &str, run_id: &str) -> Result<RunDetail> {
- let db = quire
- .db_pool()
- .lock()
- .map_err(|_| crate::error::Error::Io(std::io::Error::other("db mutex poisoned")))?;
+ let db = quire.db_pool();
let run = db.query_row(
"SELECT id, outcome, sha, ref_name, created_at, dispatched_at, resolved_at
diff --git a/quire-server/src/quire/web/handlers.rs b/quire-server/src/quire/web/handlers.rs
index 2eedbba..c0c2b26 100644
--- a/quire-server/src/quire/web/handlers.rs
+++ b/quire-server/src/quire/web/handlers.rs
@@ -322,8 +322,7 @@ mod tests {
dispatched: Option<i64>,
resolved: Option<i64>,
) {
- let pool = self.quire.db_pool();
- let db = pool.lock().expect("lock");
+ let db = self.quire.db_pool();
db.execute(
"INSERT INTO runs (id, repo, ref_name, sha, pushed_at_ms,
created_at, dispatched_at, resolved_at, outcome)
@@ -342,8 +341,7 @@ mod tests {
started: Option<i64>,
finished: Option<i64>,
) {
- let pool = self.quire.db_pool();
- let db = pool.lock().expect("lock");
+ let db = self.quire.db_pool();
db.execute(
"INSERT INTO jobs (run_id, job_id, state, exit_code, started_at_ms, finished_at_ms)
VALUES (?1, ?2, ?3, ?4, ?5, ?6)",