SOHEE KIMWEB DEVELOPER

어떤 경험이 궁금하세요?

ENGINEERING / WEBSOCKET DEVICE CONTROL

ONE SIGNAL, MANY SCREENS

06

스케줄 그룹마다 방을 나누고, 00분과 30분에는 하나가 전체를 맞춥니다.

아이파크몰 DID는 스케줄 그룹(SCH_SECT)마다 Socket.IO 방을 만듭니다. 평소에는 그룹별로 독립 재생하고, 그중 LED는 매시 00분과 30분에 약 10분 동안 전체 화면이 같은 콘텐츠를 보도록 맞춘 뒤, 각 방은 원래 그룹 스케줄로 돌아갑니다.

  1. 01그룹 → 방

    SCH_SECT

    같은 스케줄 그룹끼리 한 방
  2. MY CONTRIBUTION
    02역할

    Leader · Member

    첫 입장 단말이 리더
  3. MY CONTRIBUTION
    03프리로드

    preloadNext

    전환 약 4초 전 DOM 준비
  4. MY CONTRIBUTION
    04재생

    playNext

    같은 시점 페이드 전환

BEFORE

화면마다 재생 시계가 어긋나면 전환이 끊겨 보였습니다.

파사드와 LED가 같은 공간에 있어도 스케줄이 다르면 각자 다음 파일을 읽습니다. 네트워크 지연까지 겹치면 전환 시점이 어긋납니다.

AFTER

리더가 준비와 재생 시점만 보내고, 파일은 각 단말이 미리 붙입니다.

서버는 방을 유지하고 명령을 중계합니다. 실제 영상·이미지는 단말이 받아 숨긴 DOM으로 준비한 뒤, playNext에서 한 번에 올립니다.

01 / ROOM AND LEADER

스케줄 그룹마다 방을 두고, 리더만 명령을 내게 했습니다.

PROBLEM

모든 단말이 제각각 다음 파일을 고르면 같은 스케줄도 어긋납니다.

CMS XML의 SCH_SECT로 단말을 그룹 나눕니다. LED와 FACADE는 평소 다른 리스트를 재생하므로, 같은 그룹의 화면만 한 방으로 묶어야 전환이 맞습니다. 명령을 아무 단말이나 보내면 시계가 두 개가 됩니다.

SOLUTION

방에 처음 들어온 단말을 리더로 두고, 방 명령은 리더만 통과시킵니다.

Socket.IO 서버는 joinRoom 때 리더가 없으면 그 소켓을 리더로 둡니다. 방 멤버에게 보내는 명령은 보낸 쪽이 리더가 아니면 무시합니다. 리더가 끊기면 남은 멤버 중 첫 번째가 리더가 되고, role 이벤트로 스케줄 루프를 이어받습니다.

  1. 01리더 이전

    방장이 나가면 룸 멤버 목록의 첫 번째 단말을 승격합니다. 각 단말이 보관한 스케줄 상태를 바탕으로 현재 재생을 유지하며 제어 역할을 이어받습니다.

  2. 02늦은 입장

    재접속한 멤버는 방 입장 후 현재 스케줄을 요청합니다. 응답받은 콘텐츠를 먼저 개별 재생하고 다음 콘텐츠 명령부터 그룹과 동기화합니다.

  3. 03로컬 폴백

    연결 오류면 리더 없이 같은 1초 스케줄 루프를 로컬에서 돌려 화면이 멈추지 않게 합니다.

02 / PRELOAD THEN PLAY

전환 순간에 파일을 받지 않고, 숨긴 DOM을 올립니다.

리더는 재생 시간에서 약 4초 전에 preloadNext를 보내고, 끝나기 약 1초 전에 playNext를 보냅니다. 플레이어는 다음 img·video를 숨긴 채로 붙인 뒤, 재생 신호에서 페이드인하고 이전 노드를 제거합니다. WAVE 타입은 한 콘텐츠의 여러 파일을 같이 준비해 이어진 화면도 같은 타이밍에 바꿉니다.

명령 범위

구분이벤트동작
방 명령sendCommandToRoomMembers같은 SCH_SECT 멤버만. 리더가 아니면 서버가 보내지 않음
전체 명령sendCommandToAllMembersLED 공통 시간에 연결된 모든 단말
멤버 → 리더requestToLeader늦게 들어온 단말이 현재 재생 정보를 요청
리더 → 멤버respondToMember현재 콘텐츠를 개별 재생하도록 응답하고 다음 전환부터 그룹 동기화

03 / LED OVERRIDE

00분과 30분에는 LED가 방 밖으로 명령을 넓히고, 끝나면 그룹 스케줄로 되돌립니다.

PROBLEM

파사드 스케줄만 돌리면, 정각 공통 영상이 화면에 섞이지 않습니다.

평소 각 그룹 방은 자기 리스트만 재생합니다. 00분과 30분에 모든 화면이 LED 콘텐츠를 같이 보려면, 방 단위 명령만으로는 다른 그룹 단말이 따라오지 않습니다.

SOLUTION

00–10분, 30–40분은 전체 명령으로 LED를 맞추고, 끝나면 방 명령으로 복귀합니다.

이 프로젝트에서는 각 단말이 그룹 스케줄과 LED 공통 스케줄을 시간에 맞춰 전환합니다. LED 리더가 공통 구간 시작에 전체 재생 명령을 보냅니다. 그 시간 동안 파사드 리더는 방 루프를 돌리지 않습니다. 10분·40분이 되면 각 방은 원래 playType 리스트를 처음부터 다시 재생합니다.

RESULT

그룹별 방 재생과 00분·30분 전체 공통 재생을 같은 신호 체계로 운영하게 되었습니다.

서버는 방과 리더만 관리하고, 화면은 프리로드한 DOM을 올리는 쪽으로 역할을 나눴습니다. 각 기기에 재생 가능한 콘텐츠와 스케줄이 있으면 리더 연결이 끊겨도 재생을 이어가고, 재접속 후 다음 콘텐츠 전환부터 동기화에 합류하도록 구성했습니다.

Leader failover DOM preload LED window 00 / 30

04 / 재생 유지와 생존 감시

그룹 동기화와 화면 복구를 따로 다뤘습니다.

재생 동기화

방장 승계와 재접속은 다른 상황입니다.

방장 연결이 끊겼을 때는 나머지 단말의 재생을 유지한 채 첫 번째 룸 멤버가 제어 역할을 이어받습니다. 새로 접속한 단말은 현재 콘텐츠를 우선 재생하고 다음 전환 신호부터 싱크를 맞춥니다. 콘텐츠가 준비되어 있으면 동기화를 기다리는 동안에도 화면을 채울 수 있습니다.

WINDOWS 운영 환경

STATUS가 오지 않으면 앱에서 리로드합니다.

웹 화면은 30초마다 STATUS 텍스트를 WebView 앱에 전송합니다. 앱은 분 단위로 수신 여부를 검사하고, 신호가 없으면 강제로 리로드합니다. 이 생존 감시는 재생 명령과 별도의 흐름이며 Android에는 적용하지 않았습니다.

05 / 서버 실행과 로그 관리

사용자 세션과 서버 실행을 분리했습니다.

NSSM · WINDOWS SERVICE

로그아웃 후에도 유지하고, 부팅 시 자동 시작

Windows 환경에서는 NSSM으로 WebSocket 서버를 서비스에 등록했습니다. 사용자 로그인 상태에 의존하지 않고 실행을 유지하며, 시스템을 껐다 켠 뒤에도 서비스를 자동 시작하도록 설정했습니다. PM2를 통한 Node.js 프로세스 운영 경험도 함께 갖췄습니다.

LOGROTATE

로그가 무한히 쌓이지 않도록 순환 관리

계속 실행되는 서버의 로그가 누적되지 않도록 logrotate를 적용했습니다. 동기 재생 로직뿐 아니라 장기 운영에 필요한 실행 방식과 로그 관리도 함께 구성했습니다.