같은 진행자 계정의 다중 탭에서 Waiting for guest 고착 수정 완료 PPI-1311

마지막 업데이트 2026-09-18

작성: 2026-09-18PR #1113영향 범위: apps/socket · apps/web

결론

같은 진행자 계정으로 대시보드 탭과 룸 모니터 탭을 동시에 열면, 계정 ID 하나를 키로 사용하던 서버의 모니터 presence가 두 번째 소켓으로 덮어써졌다. 룸 모니터는 다음 45초 갱신에서 현재 소켓으로 인정되지 않아 권한과 룸 claim을 잃었고, 게스트 입장 뒤 상태 요청은 unauthorized가 됐다. 웹 화면은 이 응답을 대기 상태와 구분하지 않아 Waiting for guest가 계속 표시됐다.

수정 후: 외부 peerId는 계정 ID를 유지하면서 내부 Map·Redis 저장 키를 monitor-presence:{accountId}:{socketId}로 분리한다. 두 탭의 presence가 독립적으로 갱신되고, 권한 상실 시 클라이언트에는 별도 이벤트와 연결 끊김 안내가 전달된다.

증상과 실행 경로

  1. 룸 모니터가 MONITOR_CONNECTED로 presence를 등록한다.
  2. 같은 계정의 대시보드가 등록되며 기존 peers[principal.sub].socketId가 대시보드 소켓으로 바뀐다.
  3. 룸 claim의 갱신 tick(기본 45초)이 getTrustedMonitorPresence 검사를 실패시킨다.
  4. revokeLocalMonitoringAuthority가 claim을 제거하지만, 수정 전에는 클라이언트 통보가 없었다.
  5. 게스트 입장 후 host-request-room-state가 unauthorized로 거절되고 화면은 기존 대기 문구에 남는다.
룸 모니터 socket A 등록
  → peers[accountId] = socket A
대시보드 socket B 등록
  → peers[accountId] = socket B   // 수정 전 덮어쓰기
45초 갱신
  → socket A !== socket B
  → 룸 claim 회수
게스트 입장
  → 상태 요청 unauthorized
  → Waiting for guest 고착

코드 근거와 변경

영역구현 경로변경
Presence 저장apps/socket/src/sfu-socket/handlers/connection-handlers.ts
MONITOR_CONNECTED, MONITOR_DISCONNECTED
storageKey를 계정·소켓 단위로 생성하고 현재 소켓의 presence만 등록·삭제
피어 저장소apps/socket/src/sfu-socket/peer-ops.ts
apps/socket/src/redis/peer-store.ts
외부 peerId와 내부 Map·Redis 키를 분리해 저장·삭제 경로를 일치시킴
권한 검사apps/socket/src/sfu-socket/handlers/monitoring-handlers.ts
getTrustedMonitorPresence
계정 단일 조회 대신 계정·현재 socketId·presence 종류를 함께 확인
권한 상실 통보MONITOR_AUTHORITY_REVOKED갱신 실패 사유와 영향 룸을 서버 로그·소켓 이벤트로 전달
화면 상태apps/web/entities/host-socket/model/use-host-socket.ts
apps/web/shared/ui/monitor-media-display.tsx
isMonitorAuthorityLost를 통해 대기 화면과 연결 상실 화면을 분리

Before / After

Before
같은 계정의 두 번째 소켓이 첫 번째 presence의 socketId를 덮어쓴다. 룸 모니터는 실제로 연결돼 있어도 서버 권한을 잃고, 클라이언트는 unauthorized를 대기 상태로 표시한다.
After
각 소켓이 독립 presence를 갖는다. 룸 claim의 소유권은 기존처럼 룸 단위로 유지되며, 권한 갱신 실패가 발생하면 연결 상실 상태를 사용자에게 보여준다.
중요한 결정: 외부 메시지의 계정 기반 peerId 계약은 유지하고, 저장소 식별자만 분리했다. 이로써 호스트 목록과 기존 모니터 claim 식별자는 불필요하게 변경하지 않았다.

검증

운영 메모와 잔여 위험