1. 클라이언트 측 SSE 연결 (Login, Home 페이지 등)
- 연결 생성 및 재시도 로직:
connectSSE
함수에서 EventSource
객체를 생성하여 지정된 URL(/api/notification-service/connect/${userId}
)에 연결합니다.
- 연결이 성공하면
onopen
이벤트 핸들러가 실행되어 연결 상태와 URL 정보를 콘솔에 출력하고, 재시도 카운트를 초기화합니다.
- 에러가 발생하면
onerror
핸들러가 동작합니다. 만약 연결이 닫힌 상태라면(EventSource.CLOSED
) 재연결 로직이 작동하며, 최대 3회까지 지수 백오프(exponential backoff) 방식(최대 10초까지)으로 재연결을 시도합니다.
- SSE 객체는 전역 상태 관리(Zustand의
useSSEStore
)를 통해 저장되어, 여러 컴포넌트에서 접근하고 정리할 수 있습니다.
- 메시지 수신 및 처리:
onmessage
핸들러에서는 서버로부터 수신한 데이터를 JSON으로 파싱하여, 알림 메시지 또는 초대 메시지 등으로 분기 처리합니다.
- 예를 들어, 홈(Home) 페이지에서는 초대 알림이 오면
toast.custom
을 이용해 사용자에게 초대 수락/거절 UI를 표시합니다.
- 통합 흐름 예시 (로그인 후 연결):
- 로그인 성공 시 사용자 정보를 저장한 후(
setEmail
, setNickname
) SSE 연결을 시도합니다.
- 연결 실패 시, 토스트 메시지로 사용자에게 알림 연결 실패를 안내합니다.
- 홈 페이지에서는 이미 로그인된 사용자(
email
)를 기반으로 SSE 연결을 설정하며, 컴포넌트 언마운트 시 연결 정리(clean-up)를 진행합니다.
2. 서버 측 SSE 프록시 (Next.js API Route)
- 역할:
- 클라이언트의 SSE 요청을 받아 백엔드 SSE 서비스(API_BASE_URL를 통해 지정된 서비스)로 요청을 포워딩합니다.
- 백엔드에서 오는 스트림 데이터를 클라이언트가 이해할 수 있는 SSE 형식(즉,
data: ...\\n\\n
형식)으로 재구성하여 전송합니다.
- 핵심 로직:
fetch
를 사용하여 백엔드 SSE URL에 연결하고, 응답 스트림(response.body
)을 읽습니다.
ReadableStream
을 이용하여 읽어온 데이터를 텍스트 디코딩 후, 다시 TextEncoder
로 인코딩하여 클라이언트에 SSE 형식(data: ${text}\\n\\n
)으로 전달합니다.
- 스트림 읽기 중 에러 발생 시 적절한 로그를 남기고 스트림을 종료합니다.
3. 전역 상태 관리 (Zustand Store)
- SSE 상태 관리 (
useSSEStore
):
- SSE 연결 객체(
eventSource
)를 전역 상태로 관리하여, 여러 컴포넌트(예: 로그인 페이지, 홈 페이지 등)에서 SSE 연결 정보를 공유하고, 필요 시 연결을 정리할 수 있습니다.
- 사용자 상태 관리 (
useUserStore
):
- 로그인 후 사용자 이메일과 닉네임을 저장하여, SSE 연결 시 사용자 식별에 활용합니다.