Release v0.6.0
Rust CI / Test & Quality Checks (push) Canceled after 0s
Rust CI / Build Docker Image (push) Canceled after 0s

This commit is contained in:
thakares committed 2026-08-09 17:17:57 +05:30
1 parent 7069ca9db7
commit f49698bb5c
75 files changed
+11199 -7508

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
//! Poison-safe helpers for `std::sync::Mutex` around SQLite connections.
//!
//! Prefer these on request paths so a poisoned mutex returns a controlled error
//! instead of panicking the worker thread.
use crate::error::AppError;
use std::sync::{Mutex, MutexGuard};
use tracing::error;
/// Acquire a database mutex, mapping poison to [`AppError::Internal`].
///
/// Logs the mutex name (not connection contents or secrets).
pub fn lock_db<'a, T>(
mutex: &'a Mutex<T>,
name: &'static str,
) -> Result<MutexGuard<'a, T>, AppError> {
mutex.lock().map_err(|e| {
error!(mutex = name, error = %e, "database mutex poisoned");
AppError::Internal(format!("{name} mutex poisoned"))
})
}
/// Acquire a database mutex, mapping poison to a plain error string.
///
/// Useful for handlers that return `(StatusCode, String)` rather than `AppError`.
pub fn lock_db_str<'a, T>(
mutex: &'a Mutex<T>,
name: &'static str,
) -> Result<MutexGuard<'a, T>, String> {
mutex.lock().map_err(|e| {
error!(mutex = name, error = %e, "database mutex poisoned");
format!("{name} mutex poisoned")
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Mutex;
#[test]
fn lock_db_succeeds_on_healthy_mutex() {
let m = Mutex::new(42);
let g = lock_db(&m, "test").unwrap();
assert_eq!(*g, 42);
}
#[test]
fn lock_db_maps_poison() {
let m = Mutex::new(1);
let _ = std::panic::catch_unwind(|| {
let _g = m.lock().unwrap();
panic!("poison");
});
let err = lock_db(&m, "poisoned_db").unwrap_err();
match err {
AppError::Internal(msg) => assert!(msg.contains("poisoned_db")),
other => panic!("unexpected {other:?}"),
}
}
}