socket 연결 해제 시 재연결 시도
JAVASCRIPT ·socket 연결이 끊길 시 다시 연결하는 방법
연결이 끊기는 경우, StompJS는 다시 연결하기 위해서 새롭게 SockJS와 StompJS를 설정해주어야 한다는 사실을 알게 되었습니다. 이를 토대로 기존에 작성된 코드가 새로운 SockJS, StompJS를 만들 수 없어, 새롭게 만들 수 있는 형태로 변환하고 어느 컴포넌트에서든 이를 사용할 수 있게 수정했습니다.

// 기존에 작성된 형태로, 한 번 만들어진 뒤, 이를 다시 사용하는 데에 어려움이 따름
const sockServer = API.WEBSOCKET; // 들어갈 주소 설정
const sock = new SockJs(sockServer);
export const stompClient = StompJs.over(sock);
// 새롭게 작성된 형태로, getStompClient를 호출해 어디서든 다시 소켓 재연결을 시도할 수 있음
let stompClient: StompJs.Client;
export const getStompClient = () => {
const sockServer = API.WEBSOCKET; // 들어갈 주소 설정
const sock = new SockJs(sockServer);
stompClient = StompJs.over(sock);
};
getStompClient();
위와 같이, stomp에 연결을 요청할 수 있는 메소드를 만들고, 이를 에러가 발생해 끊기는 상황에서 다시 연결할 때 사용하도록 설정했습니다.
const maxRetryCount = 3;
const retryCount = useRef(0);
connectStomp({
onError: () => {
// 에러가 발생했을 때
setSocketConnect(false);
// 연결이 끊겼음을 알림
if (retryCount.current <= maxRetryCount) {
// 재시도 횟수가 아직 남아있는 경우
retryCount.current += 1;
// stomp client를 새로 만들고 socket에 연결함
getStompClient();
connectSocket();
}
},
...
});
위와 같은 형태의 코드를 작성함으로서 총 3번의 재시도를 하도록 하였고, 이후의 재시도는 없도록 설정을 해두었습니다. 하지만 이러한 식으로 진행할 경우, 노트북을 닫았다 다시 켜는 상황(네트워크와 브라우저가 자체적으로 멈추는 상황)에 대해서는 올바르게 재요청을 보내 다시 소켓은 연결하지만 와이파이를 끄는 경우는 이를 제대로 처리할 수가 없었습니다.

재시도를 하는 조건 변경하기
이러한 문제를 해결하기 위해서 첫번째로, 지속적으로 브라우저가 연결을 시도하도록 하고, 재시도를 하는 빈도는 ‘횟수’가 아니라 ‘시간’으로 설정해야한다고 판단했습니다. 이를 위해 연결이 끊긴 상황이 발생할 때 일정 시간 주기로 다시 연결을 시도하도록 기능을 추가하고자 했습니다.
처음에는 StompJS 내에 존재하는 heartbeat
이라는 것을 사용하고자 했습니다. 하지만, heartbeat
으로는 와이파이와 같은 인터넷 연결이 끊긴 상황을 인식할 수 없다는 것을 알게 됐고, setTimeout
을 통해 직접적인 확인이 필요하다고 판단했습니다.
에러로 인해 연결이 끊어지는 경우, setTImeout을 통해 정해진 시간 이후 다시 연결을 시도하도록 코드를 구성했습니다. 이를 통해 에러로 인해 소켓 연결이 끊기는 경우 주기적으로 연결을 재시도하도록 할 수 있었습니다. 그리고 연결이 완료될 경우(onSuccess
), 연결이 되지 않았던 시간(disconnectTimeRef
)을 초기화시켜 다음 연결 해제 시 다시 처음부터 계산을 할 수 있도록 했습니다.
const socketConnectRetryInterval = 5000; // ms
const socketConnectRetryIntervalMax = 10 * 60 * 1000; // 10mins
const disconnectTimeRef = useRef(0);
onError: () => {
const disconnectTime = disconnectTimeRef.current;
if (disconnectTime > socketConnectRetryIntervalMax) return;
disconnectTimeRef.current += socketConnectRetryInterval;
setSocketConnect(false);
setTimeout(() => {
getStompClient();
connectSocket();
}, socketConnectRetryInterval);
// 에러가 있는 경우 정해진 시간이 지날 때마다 요청을 보내 확인하도록 함
},
onConnect: () => {
disconnectTimeRef.current = 0;
setSocketConnect(true);
},
그리고 이제 인터넷 연결이 끊긴 것을 인지해야 할 필요가 있었는데, 이를 위해서는 브라우저의 내장 기능인 eventlistener
의 offline
을 활용했습니다. offline이 된 상황이 발생할 경우, 에러가 발생한 것과 동일하게 처리를 해주면 되었기에 위의 코드를 따로 빼내어 offline 상황에도 적용이 될 수 있도록 해주었습니다.
// 소켓 연결을 재시도하는 함수로 따로 빼냄
const retrySocketConnect = () => {
const disconnectTime = disconnectTimeRef.current;
if (disconnectTime > socketConnectRetryIntervalMax) return;
disconnectTimeRef.current += socketConnectRetryInterval;
setSocketConnect(false);
setTimeout(() => {
getStompClient();
connectSocket();
}, socketConnectRetryInterval);
};
const connectSocket = () => {
connectStomp({
onError: retrySocketConnect,
onConnect: () => {
disconnectTimeRef.current = 0;
setSocketConnect(true);
},
noticeParams: {
entryIds,
keywordIds,
onSubscribeEntries: onSubscribeNotice,
onSubscribeKeywords: onSubscribeNotice,
},
chatParams: { chatroomIds, onReceiveChat },
});
};
connectSocket();
// 연결이 끊어질 시, 연결 재시도
window.addEventListener("offline", retrySocketConnect);
