From 357f42c354d7fa62823ce27fbf7871eb7344d423 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Sun, 6 Jul 2025 13:20:28 +0300 Subject: [PATCH] Enha: db use same connection to avoid db locking --- crons/main.go | 1 + handlers/handlers.go | 9 ++------- main.go | 3 ++- repos/main.go | 27 +++++++++++++++++++++------ repos/players_test.go | 2 +- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/crons/main.go b/crons/main.go index c50b3dc..1bee68a 100644 --- a/crons/main.go +++ b/crons/main.go @@ -28,6 +28,7 @@ func (cm *CronManager) Start() { cm.CleanupRooms() cm.CleanupActions() cm.CleanupPlayersRoom() + ticker.Reset(30 * time.Second) } }() } diff --git a/handlers/handlers.go b/handlers/handlers.go index 21b06d9..715b10e 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -24,16 +24,11 @@ func init() { Level: slog.LevelDebug, AddSource: true, })) - // memcache = cache.MemCache cfg = config.LoadConfigOrDefault("") Notifier = broker.Notifier - // cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval - // bot loader - // check the rooms if it has bot_{digits} in them, create bots if have - repo = repos.NewRepoProvider("sqlite3://../gralias.db") + // repo = repos.NewRepoProvider("sqlite3://../gralias.db") + repo = repos.RP recoverBots() - // if player has a roomID, but no team and role, try to recover - // recoverPlayers() } func HandlePing(w http.ResponseWriter, r *http.Request) { diff --git a/main.go b/main.go index eef03cd..24670a8 100644 --- a/main.go +++ b/main.go @@ -62,7 +62,8 @@ func main() { // Setup graceful shutdown stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) - repo := repos.NewRepoProvider(cfg.DBPath) + // repo := repos.NewRepoProvider(cfg.DBPath) + repo := repos.RP defer repo.Close() cm := crons.NewCronManager(repo, slog.Default()) cm.Start() diff --git a/repos/main.go b/repos/main.go index 0ceddc8..36d9e9a 100644 --- a/repos/main.go +++ b/repos/main.go @@ -2,6 +2,7 @@ package repos import ( "context" + "gralias/config" "log/slog" "os" "sync" @@ -20,6 +21,7 @@ type AllRepos interface { SettingsRepo CardMarksRepo InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error) + Close() } type RepoProvider struct { @@ -28,16 +30,31 @@ type RepoProvider struct { pathToDB string } +var RP AllRepos + +func init() { + cfg := config.LoadConfigOrDefault("") + // sqlite3 has lock on write, so we need to have only one connection per whole app + // https://github.com/mattn/go-sqlite3/issues/274#issuecomment-232942571 + RP = NewRepoProvider(cfg.DBPath) +} + func NewRepoProvider(pathToDB string) *RepoProvider { db, err := sqlx.Connect("sqlite3", pathToDB) if err != nil { slog.Error("Unable to connect to database", "error", err) os.Exit(1) } - _, err = db.Exec("PRAGMA foreign_keys = ON;") - if err != nil { - slog.Error("Unable to enable foreign keys", "error", err) - os.Exit(1) + stmts := []string{ + "PRAGMA foreign_keys = ON;", + "PRAGMA busy_timeout=200;", + } + for _, stmt := range stmts { + _, err = db.Exec(stmt) + if err != nil { + slog.Error("Unable to enable foreign keys", "error", err) + os.Exit(1) + } } slog.Info("Successfully connected to database") // db.SetMaxOpenConns(2) @@ -45,9 +62,7 @@ func NewRepoProvider(pathToDB string) *RepoProvider { DB: db, pathToDB: pathToDB, } - go rp.pingLoop() - return rp } diff --git a/repos/players_test.go b/repos/players_test.go index 99f713e..383fcb4 100644 --- a/repos/players_test.go +++ b/repos/players_test.go @@ -98,7 +98,7 @@ func TestPlayersRepo_DeletePlayer(t *testing.T) { _, err := db.Exec(`INSERT INTO players (room_id, username, team, role, is_bot) VALUES (?, ?, ?, ?, ?)`, player.RoomID, player.Username, player.Team, player.Role, player.IsBot) assert.NoError(t, err) - err = repo.PlayerDelete(context.Background(), *player.RoomID, player.Username) + err = repo.PlayerDelete(context.Background(), player.Username) assert.NoError(t, err) var count int