fix: reduce SQLITE_BUSY errors under concurrent load

- Increase busy_timeout from 5s to 15s
- Set synchronous=NORMAL (safe with WAL, reduces fsync)
- Limit MaxOpenConns to 4 to reduce write lock contention
- Explicit wal_autocheckpoint=1000

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Algis Dumbris
2026-03-25 18:48:44 +02:00
co-authored by Claude Opus 4.6
parent c6c96f64be
commit 012b7f6fba
2 changed files with 12 additions and 3 deletions
+10 -1
View File
@@ -39,10 +39,19 @@ func New(ctx context.Context, dataDir string) (*DB, error) {
// Configure SQLite pragmas
pragmas := []string{
"PRAGMA journal_mode=WAL",
"PRAGMA busy_timeout=5000",
"PRAGMA busy_timeout=15000",
"PRAGMA foreign_keys=ON",
"PRAGMA synchronous=NORMAL",
"PRAGMA wal_autocheckpoint=1000",
}
// Limit connection pool to reduce write contention.
// SQLite allows one writer at a time; multiple connections competing
// for the write lock cause SQLITE_BUSY errors. Keeping MaxOpenConns
// low reduces lock contention while still allowing concurrent reads.
db.SetMaxOpenConns(4)
db.SetMaxIdleConns(2)
for _, pragma := range pragmas {
if _, err := db.ExecContext(ctx, pragma); err != nil {
db.Close()
+2 -2
View File
@@ -68,8 +68,8 @@ func TestNew(t *testing.T) {
if err != nil {
t.Fatalf("failed to query busy_timeout: %v", err)
}
if timeout != 5000 {
t.Errorf("busy_timeout = %d, want 5000", timeout)
if timeout != 15000 {
t.Errorf("busy_timeout = %d, want 15000", timeout)
}
// Verify database is usable