항해99/개발일지

20220310 개발일지 #서버 2개 돌리기 + node에서 mysql연결하기

paran21 2022. 3. 11. 23:07

유저의 로딩 완료 문제를 처리하다가, 로딩 중에 연결이 끊기면 어떻게 되지? 라는 질문이 나왔다.

기본적으로 클라이언트가 방에 들어오면 socket통신으로 연결되기 때문에, 연결이 끊기면 socket.io에서 가장 먼저 알게된다.

 

문제는 이렇게 연결이 끊긴 것을 spring 서버에서 알고 db에서 처리를 해줘야 한다는 점이다.

메인페이지에서 방 리스트를 조회할 때 방의 인원수도 같이 표시되기 때문에 업데이트를 해줘야 한다.

그래서 처음에 고민했던 것은 node에서 spring으로 바로 socket.id를 알려주는 것이다.

socket의 disconnect 이벤트 안에서 spring으로 데이터를 보내줘야 하는데 socket 통신에서 HTTP 통신을 쓸 수 있는지 알 수 없었다.(불가능하지 않을까?)

서버 간 통신은 가능하고 node와 spring이 HTTP 통신하는 케이스도 찾았는데 socket통신 쪽에서는 찾을 수 없었다.

 

또, 방장만 게임을 시작할 수 있는데 방장이 나가면 변경된 방장을 클라이언트에 알려줘야 한다.

그런데 HTTP 통신에서는 서버에서 클라이언트에게 먼저 데이터를 보낼 수 없고, socket도 (이해하고 있는게 맞다면) 서버에서 event가 시작하는 경우는 한정되어 있는 것 같다.

 

그래서 우리가 구성한 로직은 먼저 node에서 disconnet 이벤트 시 해당 유저의 socket.id를 클라이언트에 알려주고,

클라이언트는 api로 spring에게 이 값을 보내준다.

그리고 방장이 변경됬다면 변경된 socket.id를 클라이언트에게 알려주는 방식으로 구현했다.

 

그런데 추가적으로 생각하지 못한 문제가 있었다.

방에 1명이 남아있을 때 disconnect되면 알려줄 클라이언트가 없다!!

그런데 db에서 해당 유저와 방을 삭제하는 처리가 필요하다.

방 대기페이지에서 정상적으로 방 나가기로 나간다면 여기서 spring으로 요청이 들어가서 상관이 없는데,

브라우저가 종료되는 상황에서는 처리할 수가 없다.

 

이것 때문에 다시 node와 spring 간에 직접 통신하는 방법도 생각해봤는데, 그러면 방장 변경 문제를 해결할 수가 없다.

그래서 이 경우에만 node에서 db에 직접 접속해서 유저와 방을 삭제하도록 구현하기로 했다.

 


처음에 h2로 연결하려고 했는데 nodeJS는 거의 mysql이나 mongoDB를 사용하는 것 같다.

DB는 고민중이긴 하지만 우선 mysql을 생각하고 있기 때문에 node에서 먼저 연결해서 테스트해보기로 했다.

그래서 sequelize를 설치하고 mysql 연결을 시도했다.

 

그런데 보통 찾아본 예제들은 sequelize를 통해 models를 만드는 것부터 시작한다.

우리 프로젝트에서는 db관리는 기본적으로 spring이 하고 비정상적 종료와 같은 예외상황에서만 node가 그 역할을 대신하게 하려는 것이다.

sequelize를 통해 이미 생성된 db데이터를 models로 가져오는 것까지는 구현을 했는데 socket.io 안에서 sequelize 메소드가 실행되지 않았다.

여러 설정도 바꿔보고 했는데 계속 연결이 잘 되지 않아서 아에 mysql를 직접 connect하는 케이스를 참고했다.

그리고 query를 sql로 작성해서 입력했다.

socket.on('disconnect', () => {
      console.log(`[${socketToRoom[socket.id]}]: ${socket.id} exit`);
      const roomID = socketToRoom[socket.id];
      let room = users[roomID];
      if (room) {
          room = room.filter(user => user.id !== socket.id);
          users[roomID] = room;
          if (room.length === 0) {
              delete users[roomID];
              connection.connect(function(err) {
                  if (err) {
                      throw err;
                  } else {
                      connection.query(`DELETE FROM user WHERE room_id = ${roomID}`, function(err, rows, fields) {
                        console.log('delete user success');
                      })
                      connection.query(`DELETE FROM room WHERE id = ${roomID}`, function(err, rows, fields) {
                          console.log('delete room success');
                      })
                  }
              });
          }
      }
      socket.to(roomID).emit('user_exit', {id: socket.id});

      console.log(users);    
  })

sql를 join해서 삭제할 수도 있을 것 같은데 join은 익숙하지 않아서 user와 room에 각각 삭제 쿼리를 작성했다.

우선 mysql에 데이터를 넣고 테스트 했을 때는 잘 되는 것을 확인했다!!

 

내일 spring, react 쪽 작업이 다 끝나면 연결해서 테스트해보기로 했다.

 


 

이 문제들 논의하면서 기술적으로 부담이 된 부분도 있었지만(node와 spring 간 서버 연결!! 도대체 어떻게 하는 건가....) 팀원들이랑 얘기하면서 어떻게든 해결책을 찾은 것 같아서 뿌듯하다!!

node에서 mysql를 연결하지 않았다면 현재 로직에서 비정상 종료를 해결하지 못했을 것 같다.

 

전체적으로 큰 부분은 다 구현이 완료되었다보니 연결하면서 새로운 문제들이 나오고 있는데, 나름 잘 해결하면서 가고 있는 것 같아서 좋다.