From a274f1bc1eb7d9abdd077b3a3607134ea0ef821b Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Wed, 7 Jan 2026 21:48:55 +0000 Subject: [PATCH] fix: add SQLite busy_timeout to prevent database locked errors Set PRAGMA busy_timeout=5000 (5 seconds) to allow SQLite to retry when the database is locked instead of failing immediately. This fixes race conditions when multiple goroutines try to write simultaneously, particularly in tests where StoreObservation spawns async cleanup goroutines. Root cause: - StoreObservation launches goroutine -> CleanupOldObservations - Multiple concurrent cleanups caused "database is locked" errors - Without busy_timeout, SQLite fails immediately on lock contention Solution: - Add 5-second busy timeout for automatic retry on lock - Standard practice for concurrent SQLite usage - Works with existing WAL mode configuration Fixes TestObservationStore_CleanupOldObservations in CI. --- internal/db/gorm/store.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/db/gorm/store.go b/internal/db/gorm/store.go index aab5203..2e2dfa6 100644 --- a/internal/db/gorm/store.go +++ b/internal/db/gorm/store.go @@ -88,6 +88,11 @@ func NewStore(cfg Config) (*Store, error) { if _, err := sqlDB.Exec("PRAGMA synchronous=NORMAL"); err != nil { return nil, fmt.Errorf("set synchronous mode: %w", err) } + // Set busy timeout to 5 seconds to handle concurrent writes + // This allows SQLite to retry when database is locked instead of failing immediately + if _, err := sqlDB.Exec("PRAGMA busy_timeout=5000"); err != nil { + return nil, fmt.Errorf("set busy timeout: %w", err) + } return store, nil }