핵심 아이디어 및 아키텍처
구현된 Presence 기능은 사용자가 동시에 여러 Presence 키를 추적할 수 있도록 설계되었습니다. 예를 들어, 특정 클라이언트 페이지(/admin/clients/1/messages)에 접속 중인 사용자는 해당 클라이언트, 모든 클라이언트, 그리고 대시보드 전체에 대해 ‘존재’ 상태로 인식됩니다. 또한, ‘내 Presence 추적’과 ‘모두의 Presence 표시’는 별개의 로직으로 분리하여 관리됩니다.
기술 스택 및 구현 상세
- 클라이언트 측:
- 브라우저 클라이언트는 특정 키를 가진
PresenceChannel에 구독합니다. - Stimulus 컨트롤러는 Turbo Cable 연결을 활용하며, 30초마다
setInterval을 이용해 서버로 ‘touch’ 메시지를 전송하여 하트비트 역할을 수행합니다.
- 브라우저 클라이언트는 특정 키를 가진
- 서버 측:
PresenceChannel은connected,disconnected,touch액션을 처리하며, 연결 시 전달된 키를 저장합니다.UserPresenceActive Record 모델은 이러한 상태를 원자적으로(Postgres!) 영속화하고,increment,decrement,touch메서드를 호출합니다.- 상태 변경 시, GoodJob을 통해 일반 Turbo Stream Broadcast Laters가 트리거됩니다.
- 프론트엔드 시각화:
- Turbo::StreamsChannel을 통한 일반 Turbo Stream Broadcasts를 활용하여, 현재 접속 중인 사용자 아바타의 고유 DOM 요소를 추가하거나 제거하는 방식으로 시각적 업데이트를 처리합니다.
개발 과정의 난관 및 비판
- Action Cable의 개념적 복잡성:
Connection,Channel,Subscription,Consumer,Stream등 Action Cable의 다양한 개념과 용어들이 혼재되어 있어, 인터페이스의 일관성이 부족하다는 지적입니다. 특히 클라이언트 측에서consumer.subscriptions.create와 Turbo Rails의cable.subscribeTo사용 방식에서 이러한 혼란이 두드러집니다.- 서버 측에서는
Channel이Stream을 연결하고,Stream을 통해 브로드캐스트하며, 특정 클라이언트에게Channel을 통해 전송하는 복잡한 다중화 구조가 개발자의 이해를 어렵게 합니다. 저자는Stream이Channel구현에 나중에 추가된 요소일 수 있다고 추정합니다.
- 테스팅의 어려움:
- Action Cable 관련 테스트 후에는
ActionCable.server.restart를 통해 서버를 격리하고 초기화해야 하는 번거로움이 있습니다. - 데드락,
pg.exec정지, Active Record의undefined method 'count' for nil오류 등은 데이터베이스 연결이 비정상적으로 읽히거나 비동기적으로 처리될 때 발생할 수 있는 문제로 지적됩니다.
- Action Cable 관련 테스트 후에는
- 페이지 라이프사이클 관리:
data-turbo-permanent속성을 사용하더라도 Stimulus 컨트롤러와 Turbo Cable JavaScript가 페이지 로드 중 연결/해제되는 현상이 발생했습니다.- 이를 해결하기 위해
nextTick/nextFrame을 사용하거나,data-permanent-cable-stream-source라는 사용자 정의 요소를 만들어 채널 구독 해제를 지연시키는 등의 우회적인 방법이 필요했습니다. 이러한 섬세한 코딩이 요구되는 점은 일반적인 개발 흐름을 방해합니다.