You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Refactor] RTC SSE·Socket.IO·LiveKit 실시간 통신 역할 재검증 #44
현재 subscribeRtcRoomEvents는 구독 시점의 access token을 직접 읽어 expo/fetch로 SSE 요청을 보내고, non-2xx 응답은 상태 구분 없이 에러로 처리함. Host/Viewer 쪽에서는 해당 에러를 받아 backoff 후 재구독만 수행하며 refreshAuthSession()을 호출하는 경로가 없음.
일반 Axios 요청과 upload fetch는 401 발생 시 access token refresh 후 재요청하지만, SSE는 이 경로를 거치지 않음. 재구독할 때 store의 최신 access token을 다시 읽기는 하므로 다른 API 요청이 먼저 refresh를 수행한 경우 간접 복구될 수 있으나, SSE 요청만 유지되는 상황에서는 만료 토큰으로 401 재연결을 반복할 수 있음.
SSE가 RTC Room 상태를 유지하는 핵심 채널인 만큼 401 발생 시 자체적으로 인증 세션을 복구한 뒤 재구독할 수 있도록 처리 필요.
Viewer는 LiveKitRoom 컴포넌트를 통해 연결/재연결 책임을 SDK에 주로 위임하고, 앱 코드에서는 연결 오류를 UI 상태로 노출하는 정도로 처리함.
반면 Host는 LiveKit Room 연결 외에 Camera Publisher/Track lifecycle까지 함께 맞춰야 하므로 앱 레벨에서 추가 orchestration을 수행함. connectPromiseRef로 중복 connect를 방지하고, lifecycleEpochRef로 이전 연결 완료가 최신 상태를 덮지 않도록 보호하며, cleanupPromiseRef로 정리 작업을 직렬화함. 필요 시 ensureConnected()를 통해 연결을 다시 보장하는 구조임.
Host가 SDK 기본 재연결만 사용하지 않는 이유는 Room 연결 상태뿐 아니라 카메라 publish/stop, 화면 focus/active 상태, 종료 시 publisher 정리와 disconnect 순서까지 함께 일관되게 관리해야 하기 때문으로 보임. 따라서 Host/Viewer 간 재연결 전략 차이는 현재 역할 차이에 따른 의도된 설계로 판단됨.
RTC 종료 경쟁 조건은 endRoom() -> LiveKit 결과 RPC -> disconnectRoom() 순서와 Viewer의 SSE ended -> connection=null -> LiveKit unmount 흐름이 겹치면서 발생할 수 있음.
서버 endRoom() 처리 직후 SSE ended가 Viewer에 먼저 도착하면 Viewer의 LiveKit RPC handler가 제거된 뒤 Host가 결과 RPC를 호출할 수 있어, RPC 성공 여부가 네트워크 타이밍에 의존하게 됨.
현재 Viewer는 RPC를 받지 못하더라도 ROOM_ENDED fallback 이후 저장된 사진을 HTTP로 다시 조회할 수 있으므로, 수정 방향은 서버 endRoom() 성공을 RTC 종료의 기준으로 두고 결과 RPC는 best-effort 전달 경로로 낮추는 방향이 적절해 보임. 즉 RPC 실패를 Host 종료 전체 실패로 취급하지 않고 cleanup/disconnect는 그대로 완료하도록 처리.
이렇게 하면 race 자체는 남아도 기능 실패로 이어지지 않음. 다만 구현 전 아래 보장 여부는 확인 필요:
endRoom() 성공 시 결과 사진이 서버에 이미 저장되어 있어 Viewer HTTP fallback이 항상 가능할 것
LIVE 진입 이력이 있는 Viewer가 SSE ended를 받았을 때 결과 화면 fallback으로 반드시 전환될 것
RPC 실패 여부와 관계없이 Host disconnectRoom()과 세션 정리가 항상 실행될 것
Activity
lioba00700 commentedon Sep 5, 2026
SSE 재연결 정책에서 인증 만료(401) 복구 경로가 빠져 있음.
현재
subscribeRtcRoomEvents는 구독 시점의 access token을 직접 읽어expo/fetch로 SSE 요청을 보내고, non-2xx 응답은 상태 구분 없이 에러로 처리함. Host/Viewer 쪽에서는 해당 에러를 받아 backoff 후 재구독만 수행하며refreshAuthSession()을 호출하는 경로가 없음.일반 Axios 요청과 upload fetch는 401 발생 시 access token refresh 후 재요청하지만, SSE는 이 경로를 거치지 않음. 재구독할 때 store의 최신 access token을 다시 읽기는 하므로 다른 API 요청이 먼저 refresh를 수행한 경우 간접 복구될 수 있으나, SSE 요청만 유지되는 상황에서는 만료 토큰으로 401 재연결을 반복할 수 있음.
SSE가 RTC Room 상태를 유지하는 핵심 채널인 만큼 401 발생 시 자체적으로 인증 세션을 복구한 뒤 재구독할 수 있도록 처리 필요.
lioba00700 commentedon Sep 5, 2026
LiveKit 재연결 책임은 Host와 Viewer가 다르게 가져가고 있음.
Viewer는
LiveKitRoom컴포넌트를 통해 연결/재연결 책임을 SDK에 주로 위임하고, 앱 코드에서는 연결 오류를 UI 상태로 노출하는 정도로 처리함.반면 Host는 LiveKit Room 연결 외에 Camera Publisher/Track lifecycle까지 함께 맞춰야 하므로 앱 레벨에서 추가 orchestration을 수행함.
connectPromiseRef로 중복 connect를 방지하고,lifecycleEpochRef로 이전 연결 완료가 최신 상태를 덮지 않도록 보호하며,cleanupPromiseRef로 정리 작업을 직렬화함. 필요 시ensureConnected()를 통해 연결을 다시 보장하는 구조임.Host가 SDK 기본 재연결만 사용하지 않는 이유는 Room 연결 상태뿐 아니라 카메라 publish/stop, 화면 focus/active 상태, 종료 시 publisher 정리와 disconnect 순서까지 함께 일관되게 관리해야 하기 때문으로 보임. 따라서 Host/Viewer 간 재연결 전략 차이는 현재 역할 차이에 따른 의도된 설계로 판단됨.
lioba00700 commentedon Sep 5, 2026
RTC 종료 경쟁 조건은
endRoom() -> LiveKit 결과 RPC -> disconnectRoom()순서와 Viewer의SSE ended -> connection=null -> LiveKit unmount흐름이 겹치면서 발생할 수 있음.서버
endRoom()처리 직후 SSEended가 Viewer에 먼저 도착하면 Viewer의 LiveKit RPC handler가 제거된 뒤 Host가 결과 RPC를 호출할 수 있어, RPC 성공 여부가 네트워크 타이밍에 의존하게 됨.현재 Viewer는 RPC를 받지 못하더라도
ROOM_ENDEDfallback 이후 저장된 사진을 HTTP로 다시 조회할 수 있으므로, 수정 방향은 서버endRoom()성공을 RTC 종료의 기준으로 두고 결과 RPC는 best-effort 전달 경로로 낮추는 방향이 적절해 보임. 즉 RPC 실패를 Host 종료 전체 실패로 취급하지 않고 cleanup/disconnect는 그대로 완료하도록 처리.이렇게 하면 race 자체는 남아도 기능 실패로 이어지지 않음. 다만 구현 전 아래 보장 여부는 확인 필요:
endRoom()성공 시 결과 사진이 서버에 이미 저장되어 있어 Viewer HTTP fallback이 항상 가능할 것ended를 받았을 때 결과 화면 fallback으로 반드시 전환될 것disconnectRoom()과 세션 정리가 항상 실행될 것