fix(db): prevent SQLite "database is locked" errors under concurrent writes

Configure SQLite connections with WAL journal mode, a 5-second busy
timeout, shared cache, and a max of 1 open connection. SQLite only
supports a single writer at a time, so without these settings concurrent
API requests (e.g. bulk task creation) would immediately fail with
"database is locked" instead of waiting and retrying.
This commit is contained in:
kolaente
2026-03-02 12:37:17 +01:00
parent 1ba6a74383
commit 79dbb40985
2 changed files with 16 additions and 2 deletions

2
.gitignore vendored
View File

@@ -9,6 +9,8 @@ config.yml.sample
!.gitea/ISSUE_TEMPLATE/config.yml
docs/themes/
*.db
*.db-shm
*.db-wal
Run
dist/
cover.*

View File

@@ -250,7 +250,13 @@ func initSqliteEngine() (engine *xorm.Engine, err error) {
}
if path == "memory" {
return xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
engine, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared&_busy_timeout=5000")
if err != nil {
return
}
engine.SetMaxOpenConns(1)
engine.SetMaxIdleConns(1)
return
}
// Log the resolved database path
@@ -276,7 +282,13 @@ func initSqliteEngine() (engine *xorm.Engine, err error) {
_ = os.Remove(path) // Remove the file to not prevent the db from creating another one
}
return xorm.NewEngine("sqlite3", path)
engine, err = xorm.NewEngine("sqlite3", path+"?cache=shared&_busy_timeout=5000&_journal_mode=WAL")
if err != nil {
return
}
engine.SetMaxOpenConns(1)
engine.SetMaxIdleConns(1)
return
}
// getUserDataDir returns the platform-appropriate directory for application data