프로젝트를 진행하면서, 전자결재 시스템과 같은 상태 기반 데이터를 실시간으로 갱신해야 하는 요구사항이 생겼습니다. 예를 들면, 사용자가 요청한 결재가 승인되거나 거절될 때 그 상태가 즉시 화면에 반영되어야 했습니다.
이를 위해 저희는 여러 기술적 대안을 고민했고, 최종적으로 Server-Sent Events(SSE) 를 사용하기로 결정했습니다.
왜 WebSocket이 아닌 SSE를 선택했을까?
처음에는 자연스럽게 WebSocket을 떠올렸습니다. WebSocket은 양방향 통신이 가능하고, 대규모 실시간 애플리케이션(예: 채팅 서비스)에서는 훌륭한 선택이 될 수 있습니다. 하지만 우리의 경우는 조금 달랐습니다.
- 서버 → 클라이언트 방향의 알림만 필요했습니다. (ex: 결재 상태 변경 알림)
- 클라이언트가 서버에 실시간으로 메시지를 보낼 필요는 없었습니다.
- WebSocket을 사용하면 연결 유지 및 관리 비용이 더 높아지고, 구현 복잡도가 증가합니다.
즉, 단방향 스트리밍만 필요한 상황이었기 때문에, 더 가볍고 간단한 SSE(Server-Sent Events) 가 딱 맞는 선택이었습니다.
SSE 사용 시 고려한 점
SSE는 본질적으로 HTTP 기반이기 때문에 연결이 끊어질 수 있습니다. 특히 다음과 같은 상황을 고려해야 했습니다.
- 사용자의 네트워크가 일시적으로 끊겼다가 복구되는 경우
- 브라우저가 일시적으로 리소스를 중단하거나 복구하는 경우
- 서버 측 유지 관리나 네트워크 이슈로 인해 세션이 끊기는 경우
이런 상황을 대비해 다음과 같은 정책을 수립했습니다.
- 재시도 주기(retry interval) : 기본적으로 연결이 끊어진 경우 3초 후 재시도를 하도록 설정했습니다.
- 최대 재시도 횟수 : 무한히 재시도하지 않도록, 최대 10회까지 재시도 후 실패로 처리했습니다.
- 서버가 retry 값을 명시적으로 내려주는 경우 그 값을 반영하여 유연하게 재시도 간격을 조정할 수 있도록 했습니다.
이렇게 함으로써 네트워크 환경이 불안정한 상황에서도 사용자가 자연스럽게 서비스를 이용할 수 있도록 했습니다.
메인 스레드 부하를 줄이기 위해 WebWorker 활용
SSE는 기본적으로 브라우저의 메인 스레드에서 실행됩니다. 하지만 다음과 같은 문제가 발생할 수 있었습니다.
- 사용자가 페이지를 이동하거나 다른 작업을 수행할 때, 메인 스레드에서 SSE 연결 관리 로직이 잠깐 멈추거나 딜레이 되는 현상
- 그로 인해 사용성 저하나 예상치 못한 오류 발생 가능성
이를 방지하기 위해 WebWorker를 도입했습니다.
- SSE 연결 및 이벤트 수신 로직을 WebWorker 내부에서 실행하도록 했습니다.
- 메인 스레드는 UI 렌더링과 사용자 입력 처리에만 집중할 수 있게 했습니다.
- Worker는 SSE 연결 상태를 모니터링하고, 메시지가 오면 메인 스레드로 전달(postMessage)하는 구조로 구현했습니다.
덕분에 사용자 경험(UX)이 매우 부드럽게 유지되었고, 특히 모바일 환경에서도 네비게이션 중 끊김 없이 실시간 알림이 잘 동작하는 결과를 얻을 수 있었습니다.
마치며
이번 경험을 통해 단방향 실시간 갱신이 필요한 경우 SSE를 적극 고려해볼 수 있다는 확신을 얻었습니다. 또한, 브라우저 메인 스레드를 가볍게 유지하고 안정적인 실시간 연결을 유지하기 위해 WebWorker를 통한 비동기 처리가 얼마나 중요한지도 다시 한번 체감할 수 있었습니다.
'software engineering > frontend' 카테고리의 다른 글
| Next.js App Router에서 prefetch 전략 (0) | 2025.04.28 |
|---|---|
| Next.js에서 next/image를 사용하는 이유와 optimize 설정에 대한 고민 (0) | 2025.04.28 |
| JSON-Patch: 대규모 JSON 관리를 위한 효율적인 도구 (1) | 2025.01.22 |
| KeycloakJs를 이용한 다중 계정 전환 Web Component개발기 (1) | 2025.01.22 |
| Feature-Sliced Design(FSD): 프론트엔드 아키텍처의 새로운 접근법 (0) | 2025.01.20 |
