프로젝트: Snowpeak Game — 실시간 멀티플레이 협동 타이쿤 게임 스택: Java 17, Spring Boot 3.5, Spring WebSocket(STOMP + SockJS), Spring Data Redis(Lettuce), Redis 7, JUnit 5 관련 문서: 이동 동기화 트러블슈팅


1. 한 줄 요약

플레이어 상태를 Redis Hash(room:{roomId})에 저장하는 구조에서 유령 플레이어, 같은 닉네임 덮어쓰기, room:null 키 생성, 이동마다 Redis 동기 쓰기, 이동 순서 역전을 찾아냈습니다.

HSETNX / Lua Script / 쓰기 지연(Write-Behind) / 세션 기반 식별 / STOMP 수신 순서 보장으로 해결하고, 통합 테스트 8개와 실제 Redis 테스트 3개로 검증했습니다.


2. Redis를 어떻게 쓰고 있었나

Key   : room:{roomId}            (Redis Hash)
Field : nickname                 (= playerId)
Value : PlayerState JSON         (GenericJackson2JsonRedisSerializer)
시점 기존 동작
입장 /app/join HSET room:1 nickname state 후 /topic/room.1로 브로드캐스트
이동 /app/update 이동 메시지마다 HSET room:{클라이언트가 보낸 roomId} 후 브로드캐스트
퇴장 (연결 끊김) HEXISTS → HDEL room:1 nickname → LEAVE 브로드캐스트
늦은 입장자 동기화 HVALS room:1 결과를 1명씩 convertAndSendToUser(sessionId, ...)로 전송

3. 발견한 문제와 원인

문제 ① 서버 재시작 후 "유령 플레이어"가 계속 남는다

문제 ② 같은 닉네임으로 들어오면 기존 플레이어를 덮어쓴다

문제 ③ room:null 키가 생기고, 퇴장이 반영되지 않는다