Enha: db use same connection to avoid db locking

This commit is contained in:
Grail Finder
2025-07-06 13:20:28 +03:00
parent e84941d593
commit 357f42c354
5 changed files with 27 additions and 15 deletions

View File

@ -28,6 +28,7 @@ func (cm *CronManager) Start() {
cm.CleanupRooms() cm.CleanupRooms()
cm.CleanupActions() cm.CleanupActions()
cm.CleanupPlayersRoom() cm.CleanupPlayersRoom()
ticker.Reset(30 * time.Second)
} }
}() }()
} }

View File

@ -24,16 +24,11 @@ func init() {
Level: slog.LevelDebug, Level: slog.LevelDebug,
AddSource: true, AddSource: true,
})) }))
// memcache = cache.MemCache
cfg = config.LoadConfigOrDefault("") cfg = config.LoadConfigOrDefault("")
Notifier = broker.Notifier Notifier = broker.Notifier
// cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval // repo = repos.NewRepoProvider("sqlite3://../gralias.db")
// bot loader repo = repos.RP
// check the rooms if it has bot_{digits} in them, create bots if have
repo = repos.NewRepoProvider("sqlite3://../gralias.db")
recoverBots() recoverBots()
// if player has a roomID, but no team and role, try to recover
// recoverPlayers()
} }
func HandlePing(w http.ResponseWriter, r *http.Request) { func HandlePing(w http.ResponseWriter, r *http.Request) {

View File

@ -62,7 +62,8 @@ func main() {
// Setup graceful shutdown // Setup graceful shutdown
stop := make(chan os.Signal, 1) stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM) signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
repo := repos.NewRepoProvider(cfg.DBPath) // repo := repos.NewRepoProvider(cfg.DBPath)
repo := repos.RP
defer repo.Close() defer repo.Close()
cm := crons.NewCronManager(repo, slog.Default()) cm := crons.NewCronManager(repo, slog.Default())
cm.Start() cm.Start()

View File

@ -2,6 +2,7 @@ package repos
import ( import (
"context" "context"
"gralias/config"
"log/slog" "log/slog"
"os" "os"
"sync" "sync"
@ -20,6 +21,7 @@ type AllRepos interface {
SettingsRepo SettingsRepo
CardMarksRepo CardMarksRepo
InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error) InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error)
Close()
} }
type RepoProvider struct { type RepoProvider struct {
@ -28,16 +30,31 @@ type RepoProvider struct {
pathToDB string 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 { func NewRepoProvider(pathToDB string) *RepoProvider {
db, err := sqlx.Connect("sqlite3", pathToDB) db, err := sqlx.Connect("sqlite3", pathToDB)
if err != nil { if err != nil {
slog.Error("Unable to connect to database", "error", err) slog.Error("Unable to connect to database", "error", err)
os.Exit(1) os.Exit(1)
} }
_, err = db.Exec("PRAGMA foreign_keys = ON;") stmts := []string{
if err != nil { "PRAGMA foreign_keys = ON;",
slog.Error("Unable to enable foreign keys", "error", err) "PRAGMA busy_timeout=200;",
os.Exit(1) }
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") slog.Info("Successfully connected to database")
// db.SetMaxOpenConns(2) // db.SetMaxOpenConns(2)
@ -45,9 +62,7 @@ func NewRepoProvider(pathToDB string) *RepoProvider {
DB: db, DB: db,
pathToDB: pathToDB, pathToDB: pathToDB,
} }
go rp.pingLoop() go rp.pingLoop()
return rp return rp
} }

View File

@ -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) _, 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) assert.NoError(t, err)
err = repo.PlayerDelete(context.Background(), *player.RoomID, player.Username) err = repo.PlayerDelete(context.Background(), player.Username)
assert.NoError(t, err) assert.NoError(t, err)
var count int var count int