Skip to content

fix: 푸시 유효 시간을 10분으로 단축 - #149

Merged
tnals0924 merged 1 commit into
developfrom
fix/#148
Aug 17, 2026
Merged

fix: 푸시 유효 시간을 10분으로 단축#149
tnals0924 merged 1 commit into
developfrom
fix/#148

Conversation

@tnals0924

Copy link
Copy Markdown
Member

#️⃣연관된 이슈

🎯 해결하려는 문제가 무엇인가요?

#145 에서 넣은 푸시 아웃박스의 유효 시간(TTL)이 1시간으로 너무 깁니다.

이 서비스의 알림은 전부 실시간성이 중요합니다.

  • 사용자 알림 — 대여 승인은 "지금 과방에 갈지"를 결정하는 정보입니다. 55분 뒤에 도착하면 이미 판단이 끝난 뒤입니다
  • 관리자 알림 — 대시보드에 건이 남아 있으니 늦어도 된다고 볼 수 있지만, 실제로는 학생이 과방에서 기다리는 상태입니다

늦게 도착하는 푸시는 알림으로서 가치가 없을 뿐 아니라, 상황이 끝난 뒤에 울려서 오히려 혼란을 줍니다.

❓ 왜 해결해야 하나요?

TTL은 "이 푸시가 언제까지 보낼 가치가 있는가"를 정하는 값인데, 지금 값은 그 판단과 맞지 않습니다. 1시간을 그대로 두면 이미 쓸모없어진 알림을 계속 재시도하면서 대기열만 붙잡습니다.

인앱 알림(Notification)은 그대로 저장돼 있으므로 푸시를 포기해도 정보가 사라지지 않습니다. 사용자는 앱을 열면 확인할 수 있습니다. TTL은 "지금 알림으로 끼어들 가치가 있는가"의 기준일 뿐입니다.

⭐ 어떻게 해결했나요?

유효 시간 1시간 → 10분

백오프에서 도달 불가능해진 15분 간격 제거30초 → 2분 → 5분 최대 3회, 누적 7분 30초로 유효 시간 안에 들어옵니다. TTL이 10분이면 15분 간격은 예약 단계에서 항상 만료 처리되므로, 남겨두면 "최대 4회 재시도"로 읽히지만 실제로는 3회만 도는 상태가 됩니다.

다음 재시도 시각이 유효 시간을 넘기면 예약하지 않고 즉시 EXPIRED 처리

val nextAttemptAt = now.plusSeconds(BACKOFF_SECONDS[retryCount])

// 다음 시도 시각이 이미 유효 시간을 넘긴다면 기다릴 이유가 없다
if (isExpired(nextAttemptAt)) {
    markExpired()
    return
}

기존에는 만료될 것이 뻔한 시도를 예약해 두고, 폴러가 집어간 뒤에야 만료를 확인했습니다.

🧩 이 PR의 한계 & 트레이드오프

  • 10분은 실측이 아닌 추정치입니다. FCM 장애가 실제로 얼마나 지속되는지 로그가 쌓여야 정확한 값을 알 수 있습니다
  • 재시도 기회가 4회에서 3회로 줄었습니다. 유효 시간을 줄인 이상 당연한 결과지만, 그만큼 일시 장애를 넘길 여유는 줄었습니다. 10분을 더 줄인다면 재시도 횟수도 같이 조정해야 합니다
  • 유효 시간을 알림 종류별로 나누는 방식도 검토했으나 채택하지 않았습니다 (아래 참고)

⛓️ 기존 기능에 미치는 영향

  • DDL 변경 없음, API 스펙 변경 없음. 상수와 상태 전이 규칙만 바뀝니다
  • 이미 대기 중인 아웃박스 row에도 새 기준이 적용됩니다. TIME_TO_LIVE 는 저장된 값이 아니라 created_at 과 비교하는 상수라, 배포 시점에 10분이 지난 PENDING 건은 폴러가 집어갈 때 EXPIRED 로 정리됩니다. 인앱 알림은 그대로 남습니다
  • 발송 성공 경로는 그대로입니다 — 즉시 발송이 성공하면 재시도 설정과 무관합니다

🔀 Edge Case & 실패 시나리오

상황 기존 변경 후
10분 넘게 발송 실패 지속 1시간까지 재시도 EXPIRED 로 포기 (ERROR 로그), 인앱 알림은 남음
유효 시간 40초 남기고 실패 15분 뒤로 예약 (만료 확정) 다음 간격(30초)이 들어가므로 정상 예약
유효 시간 20초 남기고 실패 예약 후 폴러가 집어가서 만료 확인 예약하지 않고 즉시 EXPIRED
배포 시점에 10분 지난 대기 건 계속 재시도 폴러가 집어갈 때 EXPIRED 로 정리

📋 검토한 대안과 선택 이유

  • 알림 종류별로 TTL 분리 (사용자 15분 / 관리자 1시간) — 관리자 알림은 대시보드에 건이 남아 있으니 길게 잡아도 된다고 봤습니다. 하지만 학생이 과방에서 기다리는 상황이라 관리자 쪽도 실시간성이 중요하고, 값이 두 개면 튜닝할 대상만 늘어납니다. 하나로 통일했습니다
  • 대여 시각(rentAt) 기준으로 유효 시간 계산 — 승인 푸시의 실제 가치는 "대여 시각까지 남은 시간"에 달려 있어 가장 정확합니다. 다만 아웃박스가 대여 도메인을 알아야 해서, 고정 TTL로 충분하다고 판단했습니다
  • TTL은 그대로 두고 백오프만 촘촘하게 — 재시도는 빨라지지만 이미 쓸모없어진 알림을 1시간 동안 붙잡는 문제는 그대로입니다

💬 리뷰 포인트

  • [r] 10분이 적절한지 봐주세요. 이 안에 30초·2분·5분 세 번의 재시도가 들어갑니다. 더 줄이면 재시도 횟수도 함께 줄여야 합니다
  • [a] 백오프 간격(30초/2분/5분)의 분포에 의견 있으시면 알려주세요

🔍 검증

  • ./gradlew test 통과 — 아웃박스 상태 전이 단위 테스트 8건 (기존 6건에서 2건 추가)
  • 바뀐 값에 맞춰 의미가 달라진 케이스를 다시 맞췄습니다
    • 마지막 재시도 예약 시각(7분 30초)이 유효 시간 안에 드는지 — 백오프와 TTL이 어긋나면 바로 깨집니다
    • 유효 시간 40초 남기고 실패하면 재시도가 예약되고, 20초 남기고 실패하면 즉시 EXPIRED — "만료될 시도는 예약하지 않는다" 규칙의 경계입니다

TTL 1시간은 이 서비스의 알림 성격에 비해 지나치게 길다. 대여 승인은 사용자가
지금 과방에 갈지 결정하는 정보고, 관리자 알림도 학생이 기다리는 상태에서
처리해야 하는 일이라 늦게 도착하면 의미가 없다.

- 유효 시간을 1시간에서 10분으로 단축
- 도달할 수 없게 된 15분 백오프 제거 (30초 → 2분 → 5분, 최대 3회, 누적 7분 30초)
- 다음 재시도 시각이 유효 시간을 넘기면 예약하지 않고 즉시 EXPIRED 처리
  (기존에는 만료될 것이 뻔한 시도를 예약해 두고 폴러가 집어간 뒤에야 만료를 확인했다)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tnals0924 tnals0924 added the bug 버그 fix label Aug 17, 2026
@tnals0924 tnals0924 self-assigned this Aug 17, 2026
@tnals0924
tnals0924 merged commit da4a161 into develop Aug 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 버그 fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: 푸시 유효 시간(TTL) 1시간은 실시간성에 비해 과하게 김

1 participant