밝을희 클태

WebSocket 이 닫히면 재연결을 해보자 본문

PongWorld 프로젝트

WebSocket 이 닫히면 재연결을 해보자

huipark 2024. 3. 13. 00:45

프로젝트를 진행 중 WebSocket이 닫히는 현상이 생겼다.

채팅을 구현하는데 채팅방에 들어가지 않고 메세지를 입력해서 WebSocket에 Send 를 하면 오류가 나서 웹소켓이 닫혀버린다. 이거는 채팅방에 들어가지 않았을 때 그냥 채팅을 입력하지 못하게 하면 그만이지만 이 외에도 WebSocket이 닫혀버린 채로 있다면 싱글톤 패턴으로 WebSocket을 사용하고 있기 때문에 나중에 큰 문제가 될 수 있기 때문에 닫히면 다시 연결하는 로직을 구현을 하기로 했다.

 

첫 번째 방식

import BaseWebSocket from './BaseWebSocket.js';
import {getToken, refreshAccessToken} from '../tokenManager.js';
import {checkConnectionSocket} from '../webSocketManager.js';

class ConnectionSocket extends BaseWebSocket {

  async connect(url) {
	
    ...
    
      this.ws.onclose = async () => {
        console.log('Connection WebSocket 닫힘');
        this.connect(url);
      };

	...
  }


}

const cws = ConnectionSocket.getInstance();
export default cws;

 

 처음에는 단순히 WebSocket이 닫히면 WebSocket Class 내부에서 onclose 이벤트가 발생하면 다시 connect() 함수를 호출하여 연결하게 했다.

 이렇게 하니까 WebSocket이 끊겨도 다시 연결은 잘 됐다. 그런데 문제가 있다. 웹소켓 연결은 다시 잘 됐지만 아무 의미가 없다 이벤트를 아무것도 설정을 해주지 않고 연결만 돼서 쓸모가 없는 WebSocket이 됐다.

 

두 번째 방식

import cws from './WebSocket/ConnectionSocket.js';
import {refreshAccessToken, getToken} from './tokenManager.js';

let tempHandler = null;

export const checkConnectionSocket = async handler => {
  if (handler) tempHandler = handler;
  return new Promise(async (resolve, reject) => {
    if (!cws.getWS()) {
      try {
        await connectionSocketConnect(handler);
        console.log('connectionSocket 재연결!');
        resolve();
      } catch (error) {
        console.log('checkConnectionSocket Error : ', error);
        reject(error);
      }
    } else if (cws.getWS().readyState === WebSocket.CLOSED) {
      try {
        await connectionSocketConnect(tempHandler);
        resolve();
      } catch (error) {
        console.log('checkConnectionSocket Error : ', error);
        reject(error);
      }
    } else resolve();
    cws.setEvent(handler);
  });
};

export const connectionSocketConnect = async handler => {
  if (!getToken().length) await refreshAccessToken();
  await cws.connect('ws://127.0.0.1:8000/ws/connection/');
  cws.setEvent(handler);
};

위 코드는 WebSocket 을 관리해 주는 코드인데  

if (handler) tempHandler = handler;
  return new Promise(async (resolve, reject) => {
    if (!cws.getWS()) {
      try {
        await connectionSocketConnect(handler);
        console.log('connectionSocket 재연결!');
        resolve();
      } catch (error) {
        console.log('checkConnectionSocket Error : ', error);
        reject(error);
      }
    }

 이 부분은 전에 새로고침이 일어났을 때 아예 WebSocket이 끊겨 버리기 때문에 새로 연결하는 로직을 추가해 주었고 이번에 추가된 부분은

if (handler) tempHandler = handler;

...

else if (cws.getWS().readyState === WebSocket.CLOSED) {
      try {
        await connectionSocketConnect(tempHandler);
        resolve();
      } catch (error) {
        console.log('checkConnectionSocket Error : ', error);
        reject(error);
      }
    }

 이 코드이다 일단 tempHandler 변수를 전역으로 두어서 처음에 정상적으로 WebSocket 을 연결할 때 handler(WebSocket Event Handler) 함수를 전역 변수에 저장을 해두고, WebSocket error 로 WebSocket 이 닫히면 

WebSocket Class 에서 connet() 함수 대신 checkConnectionSocket() 함수를 호출해서 연결과 동시에 내가 이전에 사용했던 Event 를 함께 등록을 해준다.

import BaseWebSocket from './BaseWebSocket.js';
import {getToken, refreshAccessToken} from '../tokenManager.js';
import {checkConnectionSocket} from '../webSocketManager.js';

class ConnectionSocket extends BaseWebSocket {


  async connect(url) {
	
    ...
    
      this.ws.onclose = async () => {
        console.log('Connection WebSocket 닫힘');
        await checkConnectionSocket();
      };

	...
  }


}

const cws = ConnectionSocket.getInstance();
export default cws;

 

 

 WebSocket 이 일부러 닫히는 상황을 만들어 테스트 결과 닫힘과 동시에 새로 연결이 되고 이벤트까지 잘 작동해서 사이트가 제대로 동작을 했다!

 

 하지만 여기에도 문제점이 있다 지금 WebSocket 이 닫히면 따로 Conut 나 Delay 를 주지 않아서 무한루프에 빠질거나 사이트에 부담이 갈 수도 있다. 이건 추후에 수정을 해야겠다