이 글은 Tanstack Query와 SSE를 사용하는 프로젝트에서 상태 동기화 문제를 경험한 분들을 위한 사례 공유입니다.

 

커리어비에서 알림 도메인을 개발하면서 정말 많은 트러블 슈팅이 있었다.

오늘은 그 중 하나인 “알림 아이콘 읽음 처리 업데이트” 에 대해서 이야기해보겠다.

문제 상황

먼저 커리어비에서는 SSE를 사용하여 새로운 알림이 생기면 그 여부를 boolean으로 받아온다. 그러면 이를 header의 알림 아이콘에 업데이트 해준다.

 

이슈는 여기에서 발생한다.

사용자는 알림을 보기 위해 알림 아이콘을 클릭한다.

클릭 시 /notification 으로 이동한다.

이동 후, header의 알림 아이콘이 일반 아이콘으로 되돌아가야 한다.

포인트는 무시하자…

클라이언트와 서버의 관점 차이

여기서 백엔드와의 로직이 정확히 일치하지 않는다는 점이 이슈의 시발점이었다.

우선 커리어비에서는 “알림 페이지에 진입 함” = “알림을 읽음” 으로 간주하였다.

🎨 클라이언트 입장

  • 알림 페이지에 진입 시 바로 header의 알림 아이콘이 정상으로 돌아와야 한다.

🗄️ 서버 입장

  • 새 알림들의 ID를 PATCH 요청을 통해 받고, 해당 알림들의 읽음 여부를 '안읽음' -> '읽음' 으로 업데이트한다.
  • 알림테이블에서 각 유저들의 알림과 읽음 여부를 함께 저장하고 있기 때문이다

hasNewAlarm의 T/F 변환 시점에 대해서 클라이언트와 서버 사이의 입장 차이가 발생했다.

하지만 이것 때문에 백엔드에게 데이터필드를 추가하라고 할 수는 없는 노릇이기에 나는 두 가지 방법을 생각해냈다.

해결 방안 후보

[방법 1] useEffect에서 setQueryData로 즉시 false 처리

useEffect(() => {
  queryClient.setQueryData(['userinfo'], (oldData: any) => {
    if (!oldData) return oldData;
    if (oldData.hasNewAlarm === false) return oldData;
    return {
      ...oldData,
      hasNewAlarm: false,
    };
  });
}, []);

이런 식으로 강제로 쿼리 데이터를 설정한다.

단점

  • PATCH 요청이 완료되기 전 userInfo 쿼리가 stale되어 refetch되면:
    • 서버에서는 아직 hasNewAlarm: true 상태라 다시 true로 돌아옴
    • 아이콘이 깜빡였다 다시 켜질 수 있음
  • 일관성이 깨질 가능성

[방법 2] PATCH 완료 후 refetchQueries

await PATCH(...);
queryClient.refetchQueries(['userInfo'])

PATCH가 성공하면 서버에서 변경된 userInfo 데이터를 refetch 한다.

단점

  • POST 응답이 느린 경우, 사용자가 알림 페이지 들어갔는데 헤더 알림 아이콘이 한참 후에 사라짐
    • 즉시 피드백이 없음
    • 체감상 UX가 딜레이된다고 느낄 수 있음
  • 네트워크 레이턴시 의존

UI 깜빡임이 일어날 수 있는 상황을 정리해보자면 아래와 같다.

  1. 네트워크 상태가 느린 환경 (예: 모바일 3G)
  2. 백엔드 응답 지연 (예: 1~2초 이상)
  3. 알림을 읽음 처리하는 POST 요청과, userInfo 쿼리가 둘 다 활성화 상태라 refetch 타이밍이 겹침

하지만 최대한 낙관적 업데이트 패턴을 적용하는게 UX 측면에서 좋을 것이라고 판단했다.

따라서 아래의 방법을 생각했다.

[방법 3] 뮤테이션 사용

// PATCH 요청 중에는 refetch 하지 않게
const mutation = useMutation(markNotificationsAsRead, {
  onMutate: async () => {
    // 알림 즉시 꺼지기
    queryClient.setQueryData(['userInfo'], (old) => ({ ...old, hasNewAlarm: false }));
    // 기존 쿼리 취소 (중간 갱신 방지)
    await queryClient.cancelQueries(['userInfo']);
  },
  onSuccess: () => {
    queryClient.invalidateQueries(['userInfo']);
  },
});

100% 데이터의 일관성을 유지할 수 있는 방법이 맞다.

하지만 실사용에서 알림 상태 깜빡임이 500ms 이하에 그쳤고, 사용자 피드백에서 혼란을 느낀 사례가 없었다.

따라서 뮤테이션은 오버스펙이라는 결론을 지었다.

[방법 4] setQueryData와 refetchQueries 모두 사용 + 롤백

말 그대로 위의 방법을 모두 적용한다. 이렇게 하면 데이터 무결성도 충분히 보장될 수 있다.

이제 완벽한 낙관적 업데이트 패턴을 적용하기 위해서 롤백 로직만 구현하면 된다.

롤백 로직은 아래처럼 작성하였다.

const previousUserInfo = queryClient.getQueryData(['userInfo']);
try {
  await PATCH(...);
  queryClient.refetchQueries({ queryKey: ['userinfo'] });
} catch (error) {
  // 롤백
  queryClient.setQueryData(['userInfo'], previousUserInfo);
}

 

회고

이번 경험을 통해 실시간 데이터 동기화는 단순히 UI에 표시되느냐 의 문제가 아니라, 데이터 일관성과 사용자 체감 속도, 그리고 개발 비용까지 함께 고려해야 하는 영역이라는 걸 다시 느꼈다.

 

처음에는 그냥 어차피 금방 갱신될 거니까 refetch만 해도 되겠지 라고 생각했다. 그런데 막상 테스트를 해보니, 네트워크가 느린 환경이나 저사양 기기에서는 알림 아이콘이 깜빡거리는 순간이 보였다. 이런 작은 부분도 신경쓰지 않을 수 없다.

 

그리고 중요한 건 어떤 선택을 하든 트레이드오프가 있다는 사실이다. 낙관적 업데이트를 쓰면 사용자 입장에서는 빠르게 반응하는 것처럼 보여서 좋지만, 만약 서버 처리가 실패했을 때는 롤백까지 책임져야 한다. 생각할게 많아지지만 서비스는 견고해진다. 

 

수많은 기술들이 있지만 어디에 어떻게 적용하느냐는 나의 선택하고, 구현 방안도 수두룩하지만 그중 무엇을 선택하느냐는 나의 판단에 의한다. 그 근거들도 있어야 한다.

 

이번 이슈를 통해 단순히 알림 상태를 처리하는 작업을 넘어, 기능의 복잡도를 어디까지 가져갈 것인지, 그리고 사용자 경험과 개발 효율의 균형을 어떻게 잡을지를 고민할 수 있었다. 앞으로도 파이팅!!

 


'🖌️Frontend' 카테고리의 다른 글

[Figma] 피그마  (0) 2025.02.20
힘들다. 그런데 재밌다.

 

카카오테크 부트캠프를 시작한지 벌써 3달이 지났다.

2달 동안은 온라인 기간이었고, 1달은 오프라인 기간이었다.

 

오프라인으로 전환되고 나서 정말 많은 것이 바뀌었다.

주변에 사람들이 많다 보니 오며가며 듣는 것도 많고, 동기부여도 된다. 무엇보다 워크스페이스가 너무 좋아서 공부할 맛이 난다. 

 

난생 처음으로 제대로된 기획과 설계를 해보고 있다.

빨리 이 과정을 끝내고 개발하고 싶다는 사람들이 많이 보이지만, 나는 이 과정이 재미있다. 그리고 어쩌면 개발보다 중요하다고 생각한다.

 

한 달간 매일 12시에 퇴근했다.

인생 이렇게 열심히 살아 본 건 오랜만이다. 9시부터 6시까지 프로젝트를 하고, 8시부터 3시까지 워크스페이스에서, 집에서 공부하고 있다. 

사실 이렇게 할 수 있는 건 재미있기 때문이다.

"공부가 재밌어요" 를 정말 오랜만에 느껴본다. 어렸을 때 수학공부가 재밌던 것처럼, 노트정리를 취미삼아 했던 것 처럼. 

생각해보면 사람 참 변하지 않는 것 같다.

 

신기한게 나는 다이어리는 꾸준히 못쓰는데, 복습 노트는 빠짐없이 썼다. 마찬가지로 학습 플래너는 사놓고 몇 장 못쓰고 노트 대용으로 써도, 오답 노트는 잘도 썼다.ㅋㅋ

그래도 요즘엔 노션 덕분에 손가락에 굳은살이 사라졌다.

다행이다. 평생갈 줄 알았는데.......

 

내가 또 언제 이런 환경에서 양껏 공부해볼 수 있을까.

복받은 거라고 생각한다.

할 일이 산더미 인데, 사실 오늘은 집중하지 못했다. 주말에도 할 일이 산더미다. 

나 힘들다. 근데 재밌다. 절대 포기할 수 없다.

 

이 페이지는 CSR이면 좋겠다.

'---------------------' 카테고리의 다른 글

알지 못한다는 것을 안다는 것  (0) 2025.04.17

 

모든 것은 하나의 질문에서 시작됬다.

 

# What is Javascript.

"What": 무엇

무엇이란 무엇일까.

우리는 어떤 존재를 알지 못할 때, 그 것의 이름, 분류 등에 구애받지 않고 그 존재를 "무엇" 이라고 부른다.

 

" 하지만 우리는 그 존재를 알지 못한다는 사실을 알고 있다.

 

이 사실은 나를 학부생 때 매우 힘들게 했다.

 

이게 무엇인지 아는가? 지금 이 그림을 처음 본 사람은 10초 전에 이런 존재가 있는 것을 모르고 있었다. 하지만 지금은 이것이 존재하는지 알고 있다.

이것은 뜨개 모티브 도안과 기호이다.

이제 당신은 이 것이 존재한다는 것을 알기 때문에, 뜨개 도안을 만드는 법이 알고싶을 수도 잇고, 뜨개 도안으로 작품을 만드는 방법이 알고싶을 수도 있다. 그것도 아니면 지나가다가 이 사진을 보면 아는척이라도 할 수 있다.

 

존재를 아는 것만으로도 얼마나 많은 생각과 행동을 할 수 있는가. 

 

아직도 그렇지만 유독 나는 모른다는 걸 부끄럽다고 생각한다. 그래서 모르는 것에 대해 누군가 언급하면 아는 척을 한다.

존재를 알지 못한다는 사실을 모르고 있음이 부끄럽다.

 

하지만 아는 척을 하고 지나가는 이상 나는 그것에 대해 관심을 가지고 찾아보지 않는 이상 더 알 수 없다. 

아마 나중에도 그 것에 대해 들으면 또 아는 척을 할 것이다.

 

사실 모른다고 해서 면박주거나 무시하는 사람은 없을 텐데 말이다.

(만약 있다면 그 사람이 무례한거다.)

대부분은 친절히 설명해줄 것이다. 그렇게 내가 아는 것이 많아지는 거다.

 

그래서 요즘에는 모르는 건 모른다고 말하는 연습을 하고 있다.

 

" 모른다는 걸 인정하는 순간 나는 모른다는 사실을 알게 된다.

 

 

'---------------------' 카테고리의 다른 글

[카테부 2기] 3달차  (0) 2025.04.25

https://www.itworld.co.kr/article/3950197/%ec%83%88-%eb%aa%a8%eb%8d%b8-%ea%b3%b5%ea%b0%9c-%ec%9d%b4%ed%9b%84-%ec%8b%9c%ec%8a%a4%ed%85%9c-%ea%b3%bc%eb%b6%80%ed%95%98%ec%98%a4%ed%94%88ai%c2%b7%ea%b5%ac%ea%b8%80-%ec%88%98%ec%9a%94.html

 

새 모델 공개 이후 시스템 과부하…오픈AI·구글, 수요 앞에 멈춰 섰다

최근 구글과 오픈AI가 선보인 새로운 생성형 AI 모델로 인해 양사의 데이터센터에 과부하가 걸렸다. 두 업체 모두 급증한 수요를 감당하기 위해 대응에 나섰다. 오픈AI는 과거에도 AI 인프라가 과

www.itworld.co.kr


내용 정리

최근 구글의 제미나이 2.5 AI 모델과, 오픈AI의 4o image generation을 공개하면서 양사의 데이터센터에 과부하가 걸렸다. chatGPT의 서비스는 주로 엔비디아 GPU에 의존하고 있는데, 오픈 AI는 시스템이 개선될 떄까지 GPU 기반 AI 생성 기능 사용을 제한하는 속도 제한을 도입했다.

구글은 제미나이 실행에 자체 제작 TPU를 사용한다. TPU는 GPU보다 AI, 그래픽 등을 더 잘 처리하는 칩이다. 

엔비디아의 GPU는 전력을 대량으로 소모하고 있다. 과부하가 걸리거나 과열되면 자동으로 스로틀링 현상이 발생한다. 이는 성능 하락으로 이어진다.

🎀스로틀링(Throttling)
과도한 요청이나 처리량이 생기면 과부하를 막기위해 처리량을 줄이거나 처리하는 머신의 스펙을 낮춰서 과부하를 방지하는 처리 방식
   ✅ 소프트웨어:  API 요청을 일정 시간마다 한 번만 허용한다든가, 과도한 이벤트 발생을 무시 (ex. scroll, resize 이벤트 제한, API 요청 rate limit)
   ✅ 하드웨어:  성능(클럭 속도 등)을 의도적으로 낮춰서 발열을 줄이고, 기기 손상을 방지

 

덧붙여, 이제는 컴퓨팅 자원의 부족으로 AI 확장이 지연되지는 않는다고 한다. 또한 GPT나 제미나이 같은 LLM은 소스가 너무 무거우니 모델 크기를 줄이거나 코드를 최적화하는 방향으로 성장할 수도 있다. 딥시크는 GPT보다 더 경량의 모델로 더 나은 성능을 나타냈다. 하드웨어만이 답은 아니다는 말이다.

 

내 생각

TPU 칩에 대해 기초인공지능 시간에 배운 적이 있었는데, 구글에서 자체 제작한 건 줄은 처음 알았다.

Throttling을 검색해보다가 알게 된 것인데, 지마켓은 대기열 과도화를 처리하기 위해서 redis를 사용한 redcarpet 시스템을 사용한다고 한다. 2022년 테크글이여서 아직도 사용하는 지는 알 수 없지만 max 5만 tps 까지 문제없이 처리했다고 하니 대단한거 같긴 하다.

딥시크가 GPT보다 경량의 모델로 더 나은 성능을 보여준다는 점이 여기서도 또 나온다. GPT는 대체 어떻게 만들었고, 딥시크는 대체 어떻게 만들었을까? 그리고 결국 내 컴퓨터는 GPT든 다 하드웨어가 필요하지 않는가... 한계는 있을 수 밖에 없을 것이다. 다만 그 한계를 어디까지 미루느냐의 차이일 것이다.

이 부분을 작성하면서 졸업 프로젝트로 "온디바이스 화상 회의 서비스"를 만들었을 때가 기억났다. 그때도 유저 대부분이 고성능 GPU를 장착하지 않은 노트북으로 회의를 할 것이라고 생각해서 온디바이스적 요소를 넣는데에 꽤 애를 먹었다. GPU를 넘어 TPU도 쓰이고 있는데, 미래에는 CPU가 없어질까?

+ Recent posts