diff --git a/internal/bossraid/repository.go b/internal/bossraid/repository.go index ef5f774..8baa55c 100644 --- a/internal/bossraid/repository.go +++ b/internal/bossraid/repository.go @@ -64,14 +64,13 @@ func (r *Repository) CountActiveByUsername(username string) (int64, error) { return count, err } -// FindStaleWaitingRoomsByUsername returns waiting rooms containing the given username -// that were created before the threshold. -func (r *Repository) FindStaleWaitingRoomsByUsername(username string, threshold time.Time) ([]BossRoom, error) { +// FindWaitingRoomsByUsername returns all waiting rooms containing the given username. +func (r *Repository) FindWaitingRoomsByUsername(username string) ([]BossRoom, error) { escaped := strings.NewReplacer("%", "\\%", "_", "\\_").Replace(username) search := `"` + escaped + `"` var rooms []BossRoom - err := r.db.Where("status = ? AND players LIKE ? AND created_at < ?", - StatusWaiting, "%"+search+"%", threshold). + err := r.db.Where("status = ? AND players LIKE ?", + StatusWaiting, "%"+search+"%"). Find(&rooms).Error return rooms, err } diff --git a/internal/bossraid/service.go b/internal/bossraid/service.go index f393503..5d0e56b 100644 --- a/internal/bossraid/service.go +++ b/internal/bossraid/service.go @@ -414,19 +414,29 @@ func (s *Service) RequestEntryWithTokens(usernames []string, bossID int) (*BossR } // cleanupStaleWaitingForUsers checks if any of the given users are stuck in -// a stale waiting room (older than waitingRoomTimeout) and cleans them up. -// This provides instant resolution for players who force-quit during loading. +// a waiting room whose entry token has already expired or been consumed. +// If the pending token is gone from Redis, the room is abandoned and safe to remove. +// If the token still exists, the room may have active loading players — leave it alone. func (s *Service) cleanupStaleWaitingForUsers(usernames []string) { - threshold := time.Now().Add(-waitingRoomTimeout) + ctx := context.Background() for _, username := range usernames { - rooms, err := s.repo.FindStaleWaitingRoomsByUsername(username, threshold) + rooms, err := s.repo.FindWaitingRoomsByUsername(username) if err != nil || len(rooms) == 0 { continue } + + // pending entry token이 Redis에 남아있으면 정상 로딩 중일 수 있음 → 보존 + pendingKey := pendingEntryPrefix + username + exists, _ := s.rdb.Exists(ctx, pendingKey).Result() + if exists > 0 { + continue + } + + // 토큰 만료/소비됨 → 방 abandoned 확정, 정리 for _, room := range rooms { - log.Printf("stale 대기방 정리: session=%s, player=%s", room.SessionName, username) + log.Printf("abandoned 대기방 정리 (토큰 만료): session=%s, player=%s", room.SessionName, username) if err := s.repo.DeleteRoomBySessionName(room.SessionName); err != nil { - log.Printf("stale 대기방 삭제 실패: %v", err) + log.Printf("대기방 삭제 실패: %v", err) } _ = s.repo.ResetRoomSlot(room.SessionName) }