> For the complete documentation index, see [llms.txt](https://wonjoon.gitbook.io/joons-til/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wonjoon.gitbook.io/joons-til/trustay/documentation/designing-a-traceable-push-delivery-system.md).

# Designing a Traceable Push Delivery System

(사내 보안 규정에 따라 실제 서비스, 테이블, 코드 식별자는 모두 일반화되어 있습니다)

## 배경

초기 푸시 시스템은 **하나의 푸시 요청에 여러 대상을 묶어 처리하는 구조**였습니다.\
하나의 푸시 레코드에 여러 대상(식별자)를 리스트 형태로 저장하고, 발송 시 이를 순회하며 푸시를 전송하는 방식이었습니다.

초기에는 단순하고 구현 비용이 낮은 이유로 설계가 되어있었지만,\
알림 유형이 늘어나고, 대량 발송이 본격화 되면서 아래와 같은 문제가 발생했습니다.

* 특정 대상에게만 푸시가 실패했을 때, 어느 대상이 실패했는지 추적이 어려움
* 부분 실패와 전체 실패의 경계가 불명확
* 재처리 기준이 애매하여, 실패한 일부 대상만 재발송하기 어려움
* 푸시 발송량 증가시, 처리 시간과 부하를 예측하기 어려움

문제가 발생했을 때,\
왜 실패했는지, 어떤 대상이 실패했는지를&#x20;**데이터만으로는 설명할 수 없는 상태**였습니다.

## 원인 파악

**푸시의 데이터 표현 단위가 컸다는 점**이 문제였습니다.

* 하나의 Row = 하나의 푸시 요청 + 다수의 대상
* 성공/실패 상태는 Row 단위로만 관리되고 있었습니다.

이로 인해,

* 실패 원인 분석과 재처리 판단이 로그에 의존적이었고, 정확하지 않았습니다.

즉, 추적성이 부족한 설계였습니다.

## 해결 방법

### 1. 기존 구조 유지 + 로그 기반 추적(X)

#### 방식

* 기존 다중 대상 구조를 유지
* 로그에 대상별 실패 정보를 상세히 남김

#### 기술적 동작

* 발송 루프 내부에서 대상별 로그를 기록
* 실패 대상은 로그를 통해 알 수 있고, 사후에 수동으로 대응

#### 문제점

* 로그에 의존적
* 지속적 모니터링 필요
* 사후수동 처리

### 2. 실패 대상만 별도 테이블로 분리(X)

#### 방식

* 기존 다중 대상 구조를 유지
* 실패한 대상만 별도 실패 테이블에 기록

#### 기술적 동작

* 발송 중 실패 시, 실패 대상만 추출해서 저장
* 재처리는 실패 테이블 기준

#### 문제점

* 실패에 대한 관리 포인트가 늘어남
* 불필요한 구조 확장

### 3. 푸시 발송 단위를 1Row = 1Target으로 재설계(O)

#### 방식

* 하나의 푸시 대상 = 하나의 레코드
* 푸시 발송 최소 단위를 명확하게 정의

#### 기술적 동작

* 푸시 생성 시, 대상 리스트를 미리 풀어서, 각 대상별로 개별 푸시 Row를 생성
* 각 Row는 단일 대상, 단일 상태를 가집니다.
* 발송 스케줄러는 Row 단위로 처리

## 핵심 설계

* 푸시 발송 최소 단위 = 대상 1명
* 푸시 레코드는 "요청" 단위가 아닌 "실행 단위"
* Row 단위로 성공/실패/재처리 관리
* 발송량 = 레코드 수 이기에 성능 예측 가능

이를 통해,

* 푸시 상태는 "일부 실패" -> 명확한 성공/실패
* 재처리는 실패 상태 Row만 재처리

## 결과

* 푸시 실패 원인 추적이 명확해졌습니다. (예: 토큰 만료 등)
* 부분 재처리 가능: 전체 재발송 없이, 실패 대상만 선택적 재시도
* 성능 예측 가능성 향상: 푸시 발송량과 처리 시간의 계산의 정확도 향상

반면, 트레이드 오프는

* 레코드 수 일시적 증가
* 재처리를 위한 인덱스 추가
