[최종 프로젝트] 트러블 슈팅 - 1118

2024. 11. 18. 23:51[Node.js_6기 본캠프 TIL]

채팅이 왜 여러번 나올까?

채팅이 왜 여러번 나올까?

 

위의 이미지처럼 던전에 다녀온 캐릭터가 채팅을 치면 2번, 3번씩 올라오는 버그가 발견되었다. 던전에 다녀온 횟수 만큼 채팅이 올라오는 것으로 미루어보아, townSession에 user 데이터가 중첩되어 쌓이고 있는 것 같다는 생각이 들었다.

 

 townSession에 user 데이터를 쌓는 것은 cEnterHandler가 호출될 때 뿐이므로, 해당 핸들러에서 기존 유저가 세션에 추가되는 로직을 다시 검토해보기로 했다. 

 

  let newUser;
  // 닉네임 중복 확인
  const existingPlayer = await findUserNickname(nickname);
  
  if (existingPlayer) {
    // 존재하는 유저일 경우, DB에서 기존 정보 불러오기
    newUser = existingPlayer;
  } else {
    // 새로운 사용자 생성 및 DB에 저장
    newUser = await createUser(
      nickname,
      jobClass,
      1, // 초기 레벨
      chosenJob.maxHp,
      chosenJob.maxMp,
      chosenJob.atk,
      chosenJob.def,
      chosenJob.magic,
      chosenJob.speed,
    );
  }
  
  // User 클래스 인스턴스 생성
  const user = new User(
    socket,
    newUser.id,
    nickname,
    newUser.maxHp,
    newUser.maxMp,
    newUser.atk,
    newUser.def,
    newUser.magic,
    newUser.speed,
  );
  user.job = newUser.job;
  user.level = newUser.level;

  // 위치 정보 설정
  user.position.posX = 0;
  user.position.posY = 0;
  user.position.posZ = 0;
  user.position.rot = 0;

  // 스탯 정보 설정
  user.stat.hp = newUser.maxHp;
  user.stat.maxHp = newUser.maxHp;
  user.stat.mp = newUser.maxMp;
  user.stat.maxMp = newUser.maxMp;
  user.stat.atk = newUser.atk;
  user.stat.def = newUser.def;
  user.stat.magic = newUser.magic;
  user.stat.speed = newUser.speed;

  // townSession에 사용자 추가
  await addUserAtTown(user);

 

던전에 들어갈 때 user의 id 값을 기반으로 townSession에서 user의 데이터를 지워주기 때문에, town에 다시 입장할 때 추가해주는 로직 자체는 console.log를 찍어봐도 문제가 없었다. 그렇다면 던전에 들어갈 때, 제대로 지워지지 않는 것일까?

 

놀랍게도, 세션에 들어가는 user 데이터에 id 값이 누락된 채로 들어가고 있었다. townSession에서 user 데이터를 지우기 위해 id값을 기반으로 조회하는데, id값이 없으니 삭제가 제대로 되지 못하고 쌓이기만 한 것이다.

 

기존 코드를 살펴보니, 신규 가입한 유저의 데이터를 DB에 밀어넣고 바로 newUser로 선언하고 있었다. id가 아직 부여되지 않은 상태에서 선언했으니, id값이 누락된 채로 user 데이터가 들어가고 있는 것이 당연했다. 해당 원인을 파악한 뒤, DB에서 한번 더 조회해서 id값까지 모두 넣어줄 수 있게 코드를 수정했다.

 

코드 수정 후, id값까지 정상적으로 잘 들어가는 모습

 

 

그러나, 위와 같이 수정했음에도 여전히 채팅이 여러번 올라오는 문제가 발생했다.

 

 

원인이 무엇인지 파악하기 위해 한참을 테스트하던 중, 패킷 명세서부터 다시 보던 팀원이 해답을 찾아내고야 말았다.

 

 

S_LeaveDungeon 패킷을 보내면, 클라이언트에서 자동으로 C_Enter 패킷을 자동으로 보내기 때문에 cEnterHandler가 호출되는데 S_LeaveDungeon 패킷을 보낼 때 cEnterHandler를 서버에서 호출하고 있어서 2번씩 user의 데이터가 townSession에 쌓였던 것이다.

 

 

위와 같이 cEnterHandler를 호출하는 부분을 삭제하니, 던전을 드나들어도 채팅이 한번씩만 정상적으로 출력되었다.