fix(db): set pragmas per-connection and use single pool connection

PRAGMAs executed on the pool only applied to one random connection out
of five. Move all settings to SqliteConnectOptions so every connection
gets them. Reduce max_connections to 1 to eliminate cross-connection WAL
snapshot staleness that caused 404s on newly created entities.
This commit is contained in:
Jon Seager 2026-02-09 20:36:40 +00:00
parent 436cf101d6
commit dfb89fab66
No known key found for this signature in database

View file

@ -1,5 +1,6 @@
use anyhow::Context; use anyhow::Context;
use sqlx::migrate::Migrator; use sqlx::migrate::Migrator;
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqliteSynchronous};
pub type DatabasePool = sqlx::SqlitePool; pub type DatabasePool = sqlx::SqlitePool;
type PoolOptions = sqlx::sqlite::SqlitePoolOptions; type PoolOptions = sqlx::sqlite::SqlitePoolOptions;
@ -14,50 +15,25 @@ pub struct Database {
impl Database { impl Database {
pub async fn connect(database_url: &str) -> anyhow::Result<Self> { pub async fn connect(database_url: &str) -> anyhow::Result<Self> {
let pool = { let pool = {
use sqlx::sqlite::SqliteConnectOptions;
use std::str::FromStr; use std::str::FromStr;
let options = SqliteConnectOptions::from_str(database_url) let options = SqliteConnectOptions::from_str(database_url)
.with_context(|| format!("invalid database url: {database_url}"))? .with_context(|| format!("invalid database url: {database_url}"))?
.create_if_missing(true); .create_if_missing(true)
.journal_mode(SqliteJournalMode::Wal)
.synchronous(SqliteSynchronous::Normal)
.foreign_keys(true)
.pragma("cache_size", "-8000")
.pragma("temp_store", "MEMORY")
.busy_timeout(std::time::Duration::from_secs(5));
PoolOptions::new() PoolOptions::new()
.max_connections(5) .max_connections(1)
.connect_with(options) .connect_with(options)
.await .await
.with_context(|| format!("failed to connect to database: {database_url}"))? .with_context(|| format!("failed to connect to database: {database_url}"))?
}; };
sqlx::query("PRAGMA foreign_keys = ON;")
.execute(&pool)
.await
.context("failed to enable foreign keys for sqlite")?;
sqlx::query("PRAGMA journal_mode = WAL;")
.execute(&pool)
.await
.context("failed to enable WAL journal mode for sqlite")?;
sqlx::query("PRAGMA synchronous = NORMAL;")
.execute(&pool)
.await
.context("failed to set synchronous mode for sqlite")?;
sqlx::query("PRAGMA cache_size = -8000;")
.execute(&pool)
.await
.context("failed to set cache size for sqlite")?;
sqlx::query("PRAGMA temp_store = MEMORY;")
.execute(&pool)
.await
.context("failed to set temp_store for sqlite")?;
sqlx::query("PRAGMA busy_timeout = 5000;")
.execute(&pool)
.await
.context("failed to set busy_timeout for sqlite")?;
let db = Self { pool }; let db = Self { pool };
db.migrate().await?; db.migrate().await?;
Ok(db) Ok(db)