fix(db): stop 'set sqlite pragmas' lock flake on concurrent connects

Set busy_timeout before the WAL switch and retry the pragma batch on
'database is locked' within the same 5 s budget: while a file is still in
rollback mode, a shared-lock holder upgrading for the journal_mode change
gets SQLITE_BUSY without the busy handler running, so busy_timeout alone
doesn't cover parallel opens of a fresh file. Adds a 16-thread stress test
and drops the per-module DB_INIT workaround in ai::handlers tests.

Closes #157

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cameron CordesandClaude Opus 5.5 committed 2026-10-21 10:16:14 -04:00
1 parent e8aa337442
commit e194c02393
2 files changed
+63 -16

No files matched your search

-8
View File
@@ -2129,15 +2129,7 @@ mod turn_replay_tests {
use actix_web::{App, web::Data};
use std::sync::Arc;
/// Serialize `AppState::test_state()` construction across the parallel
/// tests in this module: each build opens ~10 DAO connections to the one
/// shared `DATABASE_URL` file, and doing several at once races the WAL
/// `journal_mode` switch into a spurious "database is locked". The test
/// bodies themselves still run in parallel; only the open is gated.
static DB_INIT: std::sync::Mutex<()> = std::sync::Mutex::new(());
fn build_state() -> Data<AppState> {
let _guard = DB_INIT.lock().unwrap_or_else(|p| p.into_inner());
Data::new(AppState::test_state())
}