Enha: tx for cron

This commit is contained in:
Grail Finder
2025-07-04 12:25:20 +03:00
parent 71a2d9d747
commit c2d6812230
5 changed files with 38 additions and 41 deletions

View File

@ -29,18 +29,36 @@ func (cm *CronManager) Start() {
} }
func (cm *CronManager) CleanupRooms() { func (cm *CronManager) CleanupRooms() {
ctx := context.Background() ctx, tx, err := cm.repo.InitTx(context.Background())
if err != nil {
cm.log.Error("failed to init transaction", "err", err)
return
}
defer func() {
if r := recover(); r != nil {
if err := tx.Rollback(); err != nil {
cm.log.Error("failed to rollback transaction", "err", err)
}
panic(r)
}
}()
rooms, err := cm.repo.RoomList(ctx) rooms, err := cm.repo.RoomList(ctx)
if err != nil { if err != nil {
cm.log.Error("failed to get rooms list", "err", err) cm.log.Error("failed to get rooms list", "err", err)
if err := tx.Rollback(); err != nil {
cm.log.Error("failed to rollback transaction", "err", err)
}
return return
} }
for _, room := range rooms { for _, room := range rooms {
players, err := cm.repo.PlayerListByRoom(ctx, room.ID) players, err := cm.repo.PlayerListByRoom(ctx, room.ID)
if err != nil { if err != nil {
cm.log.Error("failed to get players for room", "room_id", room.ID, "err", err) cm.log.Error("failed to get players for room", "room_id", room.ID, "err", err)
continue continue
} }
if len(players) == 0 { if len(players) == 0 {
cm.log.Info("deleting empty room", "room_id", room.ID) cm.log.Info("deleting empty room", "room_id", room.ID)
if err := cm.repo.RoomDeleteByID(ctx, room.ID); err != nil { if err := cm.repo.RoomDeleteByID(ctx, room.ID); err != nil {
@ -48,6 +66,7 @@ func (cm *CronManager) CleanupRooms() {
} }
continue continue
} }
creatorInRoom := false creatorInRoom := false
for _, player := range players { for _, player := range players {
if player.Username == room.CreatorName { if player.Username == room.CreatorName {
@ -55,6 +74,7 @@ func (cm *CronManager) CleanupRooms() {
break break
} }
} }
if !creatorInRoom { if !creatorInRoom {
cm.log.Info("deleting room because creator left", "room_id", room.ID) cm.log.Info("deleting room because creator left", "room_id", room.ID)
for _, player := range players { for _, player := range players {
@ -73,4 +93,9 @@ func (cm *CronManager) CleanupRooms() {
} }
} }
} }
if err := tx.Commit(); err != nil {
cm.log.Error("failed to commit transaction", "err", err)
} }
}

View File

@ -47,41 +47,9 @@ func notifyBotIfNeeded(room *models.Room) {
} }
} }
// cache
// func saveState(username string, state *models.UserState) error {
// key := models.CacheStatePrefix + username
// data, err := json.Marshal(state)
// if err != nil {
// return err
// }
// memcache.Set(key, data)
// return nil
// }
// func getAllNames() []string {
// names := []string{}
// // will not scale
// session := &models.Session{}
// // filter by key size only sessions
// for _, name := range wholeMemStore {
// // xid is 20 in len
// if len(k) != 20 {
// continue
// }
// if err := json.Unmarshal(v, &session); err != nil {
// log.Error("failed to unmarshal", "error", err)
// continue
// }
// names = append(names, session.Username)
// }
// return names
// }
// can room exists without state? I think no // can room exists without state? I think no
func getFullInfoByCtx(ctx context.Context) (*models.FullInfo, error) { func getFullInfoByCtx(ctx context.Context) (*models.FullInfo, error) {
resp := &models.FullInfo{} resp := &models.FullInfo{}
// state, err := getStateByCtx(ctx)
state, err := getPlayerByCtx(ctx) state, err := getPlayerByCtx(ctx)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -251,7 +251,7 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) {
func HandleJoinRoom(w http.ResponseWriter, r *http.Request) { func HandleJoinRoom(w http.ResponseWriter, r *http.Request) {
roomID := r.URL.Query().Get("id") roomID := r.URL.Query().Get("id")
room, err := repo.RoomGetByID(r.Context(), roomID) room, err := repo.RoomGetExtended(r.Context(), roomID)
if err != nil { if err != nil {
abortWithError(w, err.Error()) abortWithError(w, err.Error())
return return

View File

@ -62,20 +62,16 @@ 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)
defer repo.Close() defer repo.Close()
cm := crons.NewCronManager(repo, slog.Default()) cm := crons.NewCronManager(repo, slog.Default())
cm.Start() cm.Start()
server := ListenToRequests(cfg.ServerConfig.Port) server := ListenToRequests(cfg.ServerConfig.Port)
go func() { go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
panic(err) panic(err)
} }
}() }()
<-stop <-stop
slog.Info("Shutting down server...") slog.Info("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)

View File

@ -2,6 +2,7 @@ package repos
import ( import (
"context" "context"
"fmt"
"gralias/models" "gralias/models"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -60,11 +61,18 @@ func (p *RepoProvider) PlayerDelete(ctx context.Context, roomID, username string
return err return err
} }
func (p *RepoProvider) PlayerSetRoomID(ctx context.Context, username, roomID string) error { func (p *RepoProvider) PlayerSetRoomID(ctx context.Context, roomID, username string) error {
db := getDB(ctx, p.DB) db := getDB(ctx, p.DB)
_, err := db.ExecContext(ctx, "UPDATE players SET room_id = ? WHERE username = ?", roomID, username) res, err := db.ExecContext(ctx, "UPDATE players SET room_id = ? WHERE username = ?", roomID, username)
if err != nil {
return err return err
} }
affected, _ := res.RowsAffected()
if affected == 0 {
return fmt.Errorf("failed to set room_id (%s) for player (%s)", roomID, username)
}
return nil
}
func (p *RepoProvider) PlayerExitRoom(ctx context.Context, username string) error { func (p *RepoProvider) PlayerExitRoom(ctx context.Context, username string) error {
db := getDB(ctx, p.DB) db := getDB(ctx, p.DB)