Enha: db use same connection to avoid db locking
This commit is contained in:
		| @@ -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) | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								main.go
									
									
									
									
									
								
							| @@ -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() | ||||||
|   | |||||||
| @@ -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,26 +30,39 @@ 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{ | ||||||
|  | 		"PRAGMA foreign_keys = ON;", | ||||||
|  | 		"PRAGMA busy_timeout=200;", | ||||||
|  | 	} | ||||||
|  | 	for _, stmt := range stmts { | ||||||
|  | 		_, err = db.Exec(stmt) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			slog.Error("Unable to enable foreign keys", "error", err) | 			slog.Error("Unable to enable foreign keys", "error", err) | ||||||
| 			os.Exit(1) | 			os.Exit(1) | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	slog.Info("Successfully connected to database") | 	slog.Info("Successfully connected to database") | ||||||
| 	// db.SetMaxOpenConns(2) | 	// db.SetMaxOpenConns(2) | ||||||
| 	rp := &RepoProvider{ | 	rp := &RepoProvider{ | ||||||
| 		DB:       db, | 		DB:       db, | ||||||
| 		pathToDB: pathToDB, | 		pathToDB: pathToDB, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	go rp.pingLoop() | 	go rp.pingLoop() | ||||||
|  |  | ||||||
| 	return rp | 	return rp | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder