발표 화면과 리모컨을 왜 WebSocket으로 나눴을까?

FlaskWebSocket실시간

문제 상황

MT 진행용 슬라이드 덱을 발표 화면 하나로만 띄우면, 진행자가 노트북 앞에 묶이고 점수·슬라이드가 기기마다 따로 놀았습니다. 폰으로 슬라이드를 넘기고 점수를 실시간으로 맞추고 싶었습니다.

해결 방법

화면을 역할로 나누고 상태를 서버에 두었습니다.

  • 발표 화면(`/`)은 슬라이드·음악 상태를 서버로 broadcast
  • 서버(Flask-SocketIO)는 상태를 캐시하고 신규 접속자에게 내려줌
  • 폰 리모컨(`/remote`)은 상태를 구독해 원격 제어
  • 점수는 POST로 받아 `scores.json`에 저장한 뒤 전 기기에 WebSocket으로 동기화
  • 폰 리모컨 ──(slide_cmd/music_cmd)──> Flask-SocketIO ──(broadcast)──> 발표 화면 + 다른 기기
    발표 화면 ──(slide_state_from_client)──> 서버 캐시 ──> 신규 접속자 동기화
    

    배포에서 한 가지 함정이 있었습니다. WebSocket broadcast는 메시지 큐(redis) 없이 gunicorn을 다중 워커로 띄우면 워커 간에 전달되지 않습니다. 그래서 `gunicorn -k eventlet -w 1`처럼 단일 워커로 운영했습니다. 또 브라우저 autoplay 정책 때문에 배경음악 첫 재생은 사용자가 한 번 클릭하도록 했습니다.

    배운 점

  • 실시간 다기기 동기화는 화면을 늘리는 것보다 상태를 어디에 두고 누가 broadcast/구독하는지를 먼저 정해야 합니다.
  • WebSocket을 쓸 때는 배포 구조(워커 수, 메시지 큐)까지 함께 봐야 합니다.
  • 보존이 필요한 상태(점수)는 파일로 영속하고, 화면 상태는 메모리 캐시로 충분했습니다.
  • 박주영 | 백엔드 개발자 포트폴리오