APNs 전송 전에 알림 후보를 거르는 방법

알림 후보, 미발송 규칙, outbox와 APNs 결과를 분리해 추적한 푸시 구조

푸시를 보내려면 APNs 토큰과 함께 사용자 의도, 관심 장소, 알림 종류, quiet hours, 원천 데이터 최신성, 중복 방지와 발송 감사 기록이 필요하다.

한강자리 알림은 한강 나들이에서 실패할 가능성을 줄이는 정보를 골라 보낸다. 발송 후보마다 보낼 조건과 억제할 조건을 함께 평가한다.

푸시는 앱을 열지 않은 사용자에게도 도착한다. 같은 원천 데이터 변화도 관심 장소와 알림 설정에 맞지 않으면 불필요한 알림이 되므로 APNs 전송 전에 발송 규칙을 적용했다.

푸시를 보내기 전에 남길 기록

서버에서는 발송 전후에 남길 기록을 다음처럼 나눈다.

영역역할
Identity설치 단위 신호를 저장
SubscriptionAPNs device token과 구독 상태를 따라감
Preference공원, 주차장, 알림 종류별 사용자 의도
Notification fact원천 데이터에서 나온 알림 후보를 정규화한 사실
Fact claim같은 fact를 두 번 다루지 않도록 claim
Delivery decision보내거나 막은 이유를 기록
Outbox실제 알림 발송을 기다리는 durable queue
Delivery attempt전송 응답과 실패 이력을 기록
Redis index빠른 후보 조회를 위한 보조 index

Postgres에는 기준 기록과 감사 기록을 남긴다. Redis는 후보 조회와 스트림 속도를 돕는다.

후보에서 발송까지 가는 길

sequenceDiagram
  autonumber
  participant iOS as iOS 앱
  participant API as 푸시 API
  participant PG as Postgres
  participant Redis as 선호 인덱스
  participant Facts as 알림 fact
  participant Worker as 푸시 워커
  participant APNs as APNs

  iOS->>API: 구독과 알림 설정 등록
  API->>PG: 설치/구독/설정 저장
  API->>Redis: 빠른 후보 조회용 인덱스 갱신
  Facts->>PG: 정규화한 알림 후보 저장
  Worker->>PG: 처리할 후보 선점
  Worker->>Redis: 대상 구독 빠르게 찾기
  Worker->>PG: 발송 규칙 평가와 결정 기록
  Worker->>PG: 바로 보낼 항목을 outbox에 추가
  Worker->>APNs: APNs에 전송
  APNs-->>Worker: 전송 결과 반환
  Worker->>PG: 시도 결과와 후속 조치 기록

delivery decision은 사용자 설정과 후보의 최신성을 평가해 발송 또는 억제 결과를 남긴다. 조건을 통과한 후보만 outbox와 APNs 전송 단계로 넘기고 나머지는 suppression reason과 함께 저장한다.

flowchart TB
  Fact["알림 fact"] --> Context["fact 점유와 후보 조회<br/>Redis 우선 · Postgres 대체"]
  Context --> Decision{"선호 설정 · 조용한 시간<br/>쿨다운 · 최신성 통과?"}
  Decision -->|억제| Suppressed["억제 결정"]
  Decision -->|push_now| Delivery["푸시 outbox<br/>APNs 전송 · 시도 기록"]

발송 전에 적용하는 억제 규칙

모든 변화를 알림으로 보내면 같은 사용자가 필요 없는 신호까지 받게 된다. 혼잡도 변화, 즐겨찾기 주차장의 급격한 감소와 관심 공원의 통제 공지는 사용자의 설정에 따라 서로 다른 발송 규칙을 적용한다.

내부 fact type은 사용자가 선택한 알림 단위로 묶어 표시한다.

  • 중요한 변화.
  • 주차 실패 방지.
  • 관심 공원의 행사와 공지.
  • 조용한 시간.
  • 반복 알림 cooldown.
  • 원천 데이터 최신성에 따른 발송 보류.

오래된 원천 데이터에서 만든 후보는 즉시 발송하지 않는다. 사용자의 이동 결정을 바꿀 수 있는 알림에는 더 엄격한 최신성 기준을 적용한다.

마지막 단계의 APNs 전송

APNs device token 등록 뒤에는 토큰과 구독 상태의 변화를 계속 처리해야 한다.

운영 중에는 다음 상태를 처리해야 한다.

  • device token이 갱신되거나 무효화되는 경우.
  • 동일 설치가 여러 구독 상태를 거치는 경우.
  • 사용자가 권한을 껐다 켜는 경우.
  • 발송 실패가 일시적인지 영구적인지 구분하는 경우.
  • 같은 알림 후보가 worker 재시작 후 중복 발송되는 경우.

outbox와 delivery attempt는 서로 다른 기록으로 둔다. outbox는 “보내야 할 일”이고 attempt는 “보내려 했던 기록”이다. APNs 응답은 감사 기록과 device token 상태 갱신에 모두 사용된다.

device token 무효, quiet hours 억제, 오래된 원천 데이터와 APNs 일시 실패는 서로 다른 후속 조치가 필요하다. delivery decision과 attempt가 이 이유를 남긴다.

이유를 이해한 뒤의 권한 요청

한강자리는 사용자가 관심 공원이나 주차장과 알림 종류를 고른 뒤 권한을 요청한다. 시스템 팝업 전에는 앱 안에서 알림의 용도와 시점을 설명한다.

알림 설정 UI는 notification_fact_type 대신 사용자가 가려는 공원과 필요한 알림 종류를 보여준다.

발송과 억제를 함께 보는 운영 기록

Postgres에는 사용자 intent, 발송 결정, outbox와 delivery attempt를 남기고 Redis index는 후보 조회에 사용했다. 운영자는 발송 성공률과 suppression reason을 함께 확인해 토큰 정리, 재시도 또는 규칙 조정을 선택할 수 있다.

Comments

댓글

    이미지 확대