- Today
- Total
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- PDO
- Oracle
- dbeaver
- 이클립스
- 백엔드
- PLSQL
- iframe
- 의존성주입
- 환경세팅
- javascript
- 쿼리개선
- 오라클
- Hostinger
- 프로시저
- spring boot
- PROCEDURE
- 클론코딩
- 엘리멘터
- sql
- 트러블슈팅
- MariaDB
- mysqli
- 티스토리챌린지
- 문제해결
- url파라미터
- 오블완
- TIL
- 워드프레스
- 워스프레스
- 오류해결
개발 공부중
[사이드 프로젝트 회고 #3] 새 글 알림이 두 번 와요 본문
2편에서 FCM 웹 푸시를 어떻게 구성했는지 정리했다. 그런데 그 글 마지막에 살짝 흘렸던 문제가 하나 있었다 — 개발 중에 PC 토큰이 정리되지 않은 채 fcm_tokens 테이블에 그대로 남아 있었던 것. 이번 글은 그 잔여 토큰이 실제로 어떤 문제를 일으켰고, 어떻게 찾아서 고쳤는지에 대한 이야기다.

증상 — 글 하나 등록했는데 알림이 두 번
새 글 알림 기능을 테스트하던 중이었다.
글을 하나 올렸는데, 폰에 알림이 두 개씩 뜨는 거다. 당연히 코드에 버그가 있다고 생각했다.

첫 번째 의심 — 서비스워커
가장 먼저 의심한 건 서비스워커였다. 포그라운드/백그라운드에서 알림을 각각 처리하는 로직이 겹쳐서 중복으로 뜨는 게 아닐까 싶어서, 이것저것 손을 댔다.
- showNotification 호출 제거
- onBackgroundMessage 핸들러 수정
- 포그라운드에서 띄우는 Notification 코드 제거
그런데 뭘 바꿔도 증상이 똑같았다. 하나를 지우면 알림이 아예 안 뜨거나, 그대로 두 번 뜨거나 둘 중 하나였다. 서비스워커 쪽 로직을 아무리 뜯어고쳐도 원인에 접근하지 못하고 있다는 느낌이 들었다.
결정적인 힌트 — PC를 끄면 알림이 하나로 줄어든다
계속 테스트하다가 패턴이 하나 보였다.
PC를 켜두면 알림이 2번 온다. PC를 끄면 알림이 1번만 온다.
이 힌트를 보고서야 방향을 잘못 잡고 있었다는 걸 깨달았다. 문제는 서비스워커 코드가 아니라, 애초에 내가 "한 사람"에게 알림을 보낸다고 생각한 것 자체였다.
FCM은 사용자에게 보내는 게 아니라, 토큰(Token)에 보내는 시스템이다. PC Chrome과 iPhone PWA는 같은 계정으로 로그인해 있어도 서로 다른 토큰을 가진다. 그러니 새 글이 등록되면 서버는 이 계정에 연결된 토큰 전부에 푸시를 보내고, PC를 켜두면 PC 토큰으로 간 알림이 PC에서, 폰 토큰으로 간 알림이 폰에서 각각 뜬다. 내 입장에서는 "두 번 왔다"고 느껴지지만, 사실은 각각 다른 기기에 정확히 한 번씩 간 것이었다.
여기까지 이해하고 나니 "PC를 켜두면 2번, 끄면 1번"이라는 현상 자체는 설명이 됐다. 그런데 이상한 점이 하나 남아 있었다. 폰 하나만 켜둔 상태로 테스트할 때도, 가끔 알림이 두 번 오는 경우가 있었던 거다. 기기는 분명 하나인데 왜 두 번이 오는 걸까.
진짜 원인 — 정리되지 않은 옛날 토큰
fcm_tokens 테이블을 직접 열어서 확인해봤다. 그리고 원인을 찾았다.
개발 초기에 테스트하면서, PC에서 '새 글 알림 받기' 버튼을 눌러 토큰을 저장했다. 이후 같은 계정으로 모바일에서도 알림을 허용했는데, 이 과정에서 기존 PC 토큰이 정리되지 않은 채 테이블에 그대로 남아 있었다. 여기에 더해서, 브라우저를 껐다 켜거나 알림 권한을 다시 요청하는 과정에서 토큰이 재발급되는 경우도 있었는데, 이때도 옛날 토큰을 지우지 않고 새 토큰을 그냥 추가로 저장하고 있었다.
즉 테이블 안에는 "이미 유효하지 않거나 중복된 옛날 토큰"들이 계속 쌓이고 있었던 거다. 겉으로는 기기 하나만 쓰는 것처럼 보여도, 실제로는 그 사용자에게 연결된 토큰이 여러 개 저장돼 있었고, send_notification()은 저장된 토큰 전부에 성실하게 알림을 보내고 있었을 뿐이었다.
$stmt = $pdo->prepare("SELECT token FROM fcm_tokens WHERE user_id = :uid");
$stmt->execute([':uid' => $to_user_id]);
$tokens = $stmt->fetchAll(PDO::FETCH_COLUMN);
foreach ($tokens as $token) {
fcm_send_to_token($token, $title, $message, $url);
}
이 코드 자체는 잘못된 게 없었다. 문제는 fcm_tokens 테이블에 지워졌어야 할 옛날 토큰이 계속 살아있었다는 것이었다.
해결 — 테이블을 정리하다
당장 눈앞의 증상을 없애기 위해 fcm_tokens 테이블을 한 번 초기화했다. 정리하고 나니 중복 알림 증상이 말끔히 사라졌다.
다만 이건 임시방편에 가까웠다. 근본적으로는 토큰을 저장하는 시점에 같은 기기(또는 같은 사용자)의 옛날 토큰을 정리하거나 갱신하는 로직이 필요하다는 걸 이 과정에서 깨달았다. 지금처럼 매번 새로 INSERT만 하는 구조로는, 토큰이 재발급될 때마다 테이블에 쓰레기 데이터가 계속 쌓일 수밖에 없는 구조였다.

돌아보며
처음엔 "알림이 두 번 온다"는 증상 하나를 두고 서비스워커 코드를 확인했다. 그런데 진짜 원인은 코드 로직이 아니라 데이터 관리 쪽에 있었다. FCM이 "토큰 단위로 발송하는 시스템"이라는 걸 이해하는 것과, 그 토큰을 DB에서 어떻게 깨끗하게 관리할지는 완전히 다른 문제였다는 걸 이번에 배웠다.