Fix: 로딩 중 강제 종료 시 stale waiting room 자동 정리
로딩 화면에서 강제 종료하면 BossRoom이 waiting 상태로 남아 재입장이 영구 차단되는 문제 수정. - waiting 상태 2분 초과 BossRoom 자동 정리 (15초 주기) - RequestEntry 시 해당 유저의 stale waiting room 선제 정리 - 연결된 RoomSlot도 idle로 리셋 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -64,6 +64,18 @@ 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) {
|
||||
escaped := strings.NewReplacer("%", "\\%", "_", "\\_").Replace(username)
|
||||
search := `"` + escaped + `"`
|
||||
var rooms []BossRoom
|
||||
err := r.db.Where("status = ? AND players LIKE ? AND created_at < ?",
|
||||
StatusWaiting, "%"+search+"%", threshold).
|
||||
Find(&rooms).Error
|
||||
return rooms, err
|
||||
}
|
||||
|
||||
// --- DedicatedServer & RoomSlot ---
|
||||
|
||||
// UpsertDedicatedServer creates or updates a server group by name.
|
||||
@@ -213,6 +225,40 @@ func (r *Repository) DeleteRoomBySessionName(sessionName string) error {
|
||||
return r.db.Unscoped().Where("session_name = ?", sessionName).Delete(&BossRoom{}).Error
|
||||
}
|
||||
|
||||
// CleanupStaleWaitingRooms deletes BossRoom records stuck in "waiting" status
|
||||
// past the given threshold and resets their associated RoomSlots to idle.
|
||||
// This handles cases where players disconnect during loading before the Fusion session starts.
|
||||
func (r *Repository) CleanupStaleWaitingRooms(threshold time.Time) (int64, error) {
|
||||
// 1. waiting 상태에서 threshold보다 오래된 방 조회
|
||||
var staleRooms []BossRoom
|
||||
if err := r.db.Where("status = ? AND created_at < ?", StatusWaiting, threshold).
|
||||
Find(&staleRooms).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(staleRooms) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 2. 연결된 슬롯을 idle로 리셋
|
||||
staleSessionNames := make([]string, len(staleRooms))
|
||||
for i, room := range staleRooms {
|
||||
staleSessionNames[i] = room.SessionName
|
||||
}
|
||||
r.db.Model(&RoomSlot{}).
|
||||
Where("session_name IN ? AND status = ?", staleSessionNames, SlotWaiting).
|
||||
Updates(map[string]interface{}{
|
||||
"status": SlotIdle,
|
||||
"boss_room_id": nil,
|
||||
})
|
||||
|
||||
// 3. BossRoom 레코드 하드 삭제
|
||||
result := r.db.Unscoped().
|
||||
Where("status = ? AND created_at < ?", StatusWaiting, threshold).
|
||||
Delete(&BossRoom{})
|
||||
|
||||
return result.RowsAffected, result.Error
|
||||
}
|
||||
|
||||
// ResetStaleSlots clears instanceID for slots with stale heartbeats
|
||||
// and resets any active raids on those slots.
|
||||
func (r *Repository) ResetStaleSlots(threshold time.Time) (int64, error) {
|
||||
|
||||
Reference in New Issue
Block a user