fix: 좀비 슬롯 정리 및 보상 실패 상태 추적
All checks were successful
Server CI/CD / lint-and-build (push) Successful in 1m5s
Server CI/CD / deploy (push) Successful in 58s

- RequestEntry() 시 CheckStaleSlots() 호출하여 좀비 슬롯 자동 정리
- 블록체인 보상 실패 시 BossRoom 상태를 reward_failed로 업데이트
- UpdateRoomStatus() 레포지토리 메서드 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-16 20:07:34 +09:00
parent befea9dd68
commit 22e0652ee3
3 changed files with 25 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ const (
StatusInProgress RoomStatus = "in_progress"
StatusCompleted RoomStatus = "completed"
StatusFailed RoomStatus = "failed"
StatusRewardFailed RoomStatus = "reward_failed"
)
// BossRoom represents a boss raid session room.

View File

@@ -219,6 +219,17 @@ func (r *Repository) ResetStaleSlots(threshold time.Time) (int64, error) {
return result.RowsAffected, result.Error
}
// UpdateRoomStatus updates only the status of a boss room by session name.
func (r *Repository) UpdateRoomStatus(sessionName string, status RoomStatus) error {
result := r.db.Model(&BossRoom{}).
Where("session_name = ?", sessionName).
Update("status", status)
if result.RowsAffected == 0 {
return fmt.Errorf("방을 찾을 수 없습니다: %s", sessionName)
}
return result.Error
}
// GetRoomSlotsByServer returns all room slots for a given server.
func (r *Repository) GetRoomSlotsByServer(serverID uint) ([]RoomSlot, error) {
var slots []RoomSlot

View File

@@ -55,6 +55,9 @@ func (s *Service) SetExpGranter(fn func(username string, exp int) error) {
// Allocates an idle room slot from a registered dedicated server.
// Returns the room with assigned session name.
func (s *Service) RequestEntry(usernames []string, bossID int) (*BossRoom, error) {
// 좀비 슬롯 정리 — idle 슬롯 검색 전에 stale 인스턴스를 리셋
s.CheckStaleSlots()
if len(usernames) == 0 {
return nil, fmt.Errorf("플레이어 목록이 비어있습니다")
}
@@ -222,6 +225,7 @@ func (s *Service) CompleteRaid(sessionName string, rewards []PlayerReward) (*Bos
// Grant rewards outside the transaction to avoid holding the lock during RPC calls
resultRewards = make([]RewardResult, 0, len(rewards))
hasRewardFailure := false
if s.rewardGrant != nil {
for _, r := range rewards {
grantErr := s.rewardGrant(r.Username, r.TokenAmount, r.Assets)
@@ -229,11 +233,19 @@ func (s *Service) CompleteRaid(sessionName string, rewards []PlayerReward) (*Bos
if grantErr != nil {
result.Error = grantErr.Error()
log.Printf("보상 지급 실패: %s: %v", r.Username, grantErr)
hasRewardFailure = true
}
resultRewards = append(resultRewards, result)
}
}
// 보상 실패가 있으면 상태를 reward_failed로 업데이트
if hasRewardFailure {
if err := s.repo.UpdateRoomStatus(sessionName, StatusRewardFailed); err != nil {
log.Printf("보상 실패 상태 업데이트 실패: %s: %v", sessionName, err)
}
}
// Grant experience to players
if s.expGrant != nil {
for _, r := range rewards {