Skip to content

매칭 상태 폴링이 통신 실패 한 번으로 영구 중단됨 #413

Description

@dev-yunseong

문제

StatusTracker.GetUserStatus는 전송 계층 실패 시 WDebug.LogErroryield break로 빠져나가면서 handler를 전혀 호출하지 않는다. MatchStatusPollerStartCoroutine 직전에 _waiting = true로 걸어두고 이 값을 HandleStatus에서만 해제하므로, 핸들러가 호출되지 않으면 _waiting이 영원히 true로 남는다. 이후 모든 Update()가 조기 return 되어 폴링이 완전히 죽는다. 같은 코루틴의 파싱/빈 상태 분기(61-66행)는 yield return handler.Invoke(null)을 제대로 호출하고 있어, 이는 의도된 설계가 아니라 분기 간 불일치다.

위치

  • client/Assets/Scripts/LobbyScene/StatusTracker.cs:49

재현 / 영향

플레이어가 큐에 들어가면 poller가 2초마다 GET /api/users/mine/status를 호출한다. 이 중 한 번이 전송 계층에서 실패하면(인그레스 502, 요청 타임아웃, 짧은 Wi-Fi 끊김, WebGL 네트워크/CORS 오류) www.result != Success → 로그 → yield break로 끝나고 HandleStatus가 실행되지 않아 _waiting이 true로 고정된다. 이후 서버가 매칭을 성사시켜 상태를 OnPlaying으로 바꿔도 클라이언트는 이를 관측하지 못한다. 로비는 계속 Matching UI를 표시하고, OnMatched가 발생하지 않으며, RecoverGameSession도 호출되지 않아 GameScene이 로드되지 않는다. 결과적으로 서버에서 이미 시작된 매치를 플레이어가 그대로 몰수당한다. 로비의 다른 경로로는 복구되지 않는다 — LobbyUIController.cs:95는 씬 로드 시 GetUserStatus를 단 한 번만 호출하는 일회성 경로다.

수정 방향

StatusTracker.GetUserStatus의 49행 yield breakyield return handler.Invoke(null); yield break;로 바꿔 전송 실패 경로가 64행의 빈 상태 경로와 동일하게 동작하도록 한다. 공용 코루틴에서 고치면 두 호출자 모두 커버된다. 추가로 MatchStatusPoller가 래퍼 코루틴(yield return inner; _waiting = false;)에서 _waiting을 해제하도록 바꾸면 이후 어떤 조기 종료가 생겨도 다시 잠기지 않는다.


심각도: high · 분류: correctness
자동 코드 리뷰(멀티 에이전트 검증 통과)에서 발견됨.

Metadata

Metadata

Assignees

Labels

fixfix bugsstale이슈가 지목한 코드가 더 이상 존재하지 않음

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions