Skip to content

Commit 86e1c7d

Browse files
committed
Fix: Add busy_timeout to SQLite connections to prevent lock errors
Problem: - Getting "database is locked" errors during concurrent operations - Archive worker reading large datasets while crawler tries to write - SQLite was failing immediately instead of waiting for lock Solution: Add _busy_timeout=5000 (5 seconds) to all SQLite connection strings - SQLite will now retry for 5 seconds before returning "database is locked" - Handles brief lock contention from concurrent read/write operations - WAL mode already allows concurrent reads, this handles write conflicts Expected behavior: - Fewer "database is locked" errors - Operations will wait briefly for locks to be released - Only fail if lock held for more than 5 seconds (indicates real deadlock)
1 parent 457048e commit 86e1c7d

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

database.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,9 @@ func openNewsDatabase(sqliteDataDir string, logger *slog.Logger) (newsDatabase,
225225
stdlib.Register("sqlite3_ext")
226226

227227
logger.Info("Opening database connection", "file", frontpageDatabaseFilename)
228-
// Connect to database
229-
ndb.db, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL", frontpageDatabaseFilename))
228+
// Connect to database with busy timeout to handle concurrent access
229+
// _busy_timeout=5000 means SQLite will retry for 5 seconds before returning "database is locked"
230+
ndb.db, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL&_busy_timeout=5000", frontpageDatabaseFilename))
230231

231232
if err != nil {
232233
return ndb, errors.Wrap(err, "open frontpageDatabase")
@@ -247,7 +248,7 @@ func openNewsDatabase(sqliteDataDir string, logger *slog.Logger) (newsDatabase,
247248
{
248249
upvotesDatabaseFilename := fmt.Sprintf("%s/upvotes.sqlite", sqliteDataDir)
249250

250-
ndb.upvotesDB, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL", upvotesDatabaseFilename))
251+
ndb.upvotesDB, err = sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL&_busy_timeout=5000", upvotesDatabaseFilename))
251252
if err != nil {
252253
return ndb, errors.Wrap(err, "open upvotesDB")
253254
}
@@ -523,13 +524,13 @@ func (ndb newsDatabase) selectStoryDetails(ctx context.Context, id int) (Story,
523524
func (ndb *newsDatabase) resetConnection() error {
524525
// Create new connections first
525526
frontpageDatabaseFilename := fmt.Sprintf("%s/%s", ndb.sqliteDataDir, sqliteDataFilename)
526-
newDB, err := sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL", frontpageDatabaseFilename))
527+
newDB, err := sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL&_busy_timeout=5000", frontpageDatabaseFilename))
527528
if err != nil {
528529
return errors.Wrap(err, "reopen frontpageDatabase")
529530
}
530531

531532
upvotesDatabaseFilename := fmt.Sprintf("%s/upvotes.sqlite", ndb.sqliteDataDir)
532-
newUpvotesDB, err := sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL", upvotesDatabaseFilename))
533+
newUpvotesDB, err := sql.Open("sqlite3_ext", fmt.Sprintf("file:%s?_journal_mode=WAL&_busy_timeout=5000", upvotesDatabaseFilename))
533534
if err != nil {
534535
newDB.Close()
535536
return errors.Wrap(err, "reopen upvotesDB")

0 commit comments

Comments
 (0)