FCM 알림 전송을 위한 비동기 배치 처리 시스템 구현으로 대량 트래픽 상황에서 시스템 안정성 및 응답성 향상
메일 서비스 특성상 단기간에 대량의 메일 수신이 발생하며, 각 메일 수신 시마다 FCM 알림을 전송해야 하는 상황이다.
동기 처리 방식으로 구현한다면 다음과 같은 문제점이 발생할 것이다:
응답 지연: 메일 수신 → Article 저장 → FCM 전송이 모두 동기로 처리되어 사용자 응답 시간이 급격히 증가
시스템 부하: 대량 메일 수신 시 FCM API 호출이 메인 애플리케이션 스레드를 블로킹
장애 전파: FCM 전송 실패가 Article 저장 프로세스에 영향을 미쳐 전체 시스템 불안정
메모리 부족: 대량의 FCM 요청을 동시에 처리할 때 메모리 사용량 급증
이러한 문제 발생을 방지하기 위해 비동기 배치 처리 시스템이 필요했다.
Feat: BatchProducer와 BatchConsumer를 상속받아 인터페이스 Article용으로 제작
Feat: BatchProducer와 BatchConsumer를 상속받은 FCM용 배치 인터페이스 생성
시스템 안정성 및 응답성 향상
Producer: Feat: FcmBatchProducer의 Redis 기반 구현체 추가
Consumer: Feat: FcmBatchConsumer의 Redis 기반 구현체 추가
장애 격리 및 부하 분산
Repository Layer: Feat: 유저 ID 기반 FcmToken 전체 조회용 repo 구현체 메서드 추가
Service Layer: Feat: fcm 비즈니스 로직에 sendFcmWhenMailReceivedBatch 추가
Orchestrator Layer: Feat: FcmTokenOrchestrator에 하위 서비스단에서 추가된 로직 추가
Controller Layer: Feat: fcm용 실시간 배치 처리 상태 모니터링 및 제어 api 제공 컨트롤러 추가
Feat: FcmBatchConsumer의 Redis 기반 구현체 추가
Feat: Article 저장 성공 시 FCM 배치 처리 호출 로직 추가
Feat: FcmBatchConsumer의 Redis 기반 구현체 추가
1. 메일 수신 → Article 도메인 배치 처리
2. Article 저장 성공 → FCM 알림 배치 큐에 추가 (비동기)
3. 즉시 사용자 응답 반환
4. 백그라운드에서 FCM 배치 Consumer가 일정 주기/크기로 알림 전송
5. 전송 실패 시 유효하지 않은 토큰 자동 삭제
firebase-service-account.json 파일을 resourses 하위에 두고 .gitignore에 추가한 상태
향후 컨테이너 환경에서 Firebase 인증 파일 마운트 작업으로 Docker Compose에서 사용할 수 있는 환경 구성 필요

commit : Feat: BatchProducer에 대한 추상클래스 구현체 생성
commit : Feat: BatchConsumer에 대한 추상클래스 구현체 생성
변경 전: 인터페이스만 사용하는 구조
Interface
├── BatchProducer<T>
├── BatchConsumer
│
├── ArticleBatchProducer
├── FcmBatchProducer
├── ArticleBatchConsumer
├── FcmBatchConsumer
│
└── 구현체들
├── ArticleRedisBatchProducerImpl
├── FcmRedisBatchProducerImpl
├── ArticleRedisBatchConsumerImpl (Redis 연결, 직렬화, 배치처리 등 중복코드)
└── FcmRedisBatchConsumerImpl (Redis 연결, 직렬화, 배치처리 등 중복코드)
모든 구현체에서 Redis 처리 로직 등 일부 코드가 중복된다는 문제 발생
변경 후: 추상클래스 + 인터페이스 구조
Interface
├── BatchProducer<T>
├── BatchConsumer
│
├── AbstractBatchProducer<T> (공통 로직)
├── AbstractBatchConsumer<T> (공통 로직)
│
├── ArticleBatchProducer
├── FcmBatchProducer
├── ArticleBatchConsumer
├── FcmBatchConsumer
│
└── 구현체들
├── ArticleRedisBatchProducerImpl (도메인 로직만)
├── FcmRedisBatchProducerImpl (도메인 로직만)
├── ArticleRedisBatchConsumerImpl (Article 처리 로직만)
└── FcmRedisBatchConsumerImpl (FCM 전송 로직만)
변경으로 인한 개선 효과
- 코드 중복 제거: ~40% 코드량 감소
- 유지보수성 향상: 공통 로직 한 곳에서 관리
- 개발 생산성: 새 배치 추가시 도메인 로직만 구현
- 관심사 분리: 인프라 로직 vs 비즈니스 로직 명확히 분리
commit : Refactor: fcmNotification에 대한 검증을 생선단계에서 실행하도록 변경
commit. : Refactor: FcmRedisBatchConsumerImpl에서 유효하지 않은 fcmToken에 대한 삭제를 repo단에서 수행하도록 변경
commit : Feat: Aritcle 하위 Batch에 추상클래스 상속
commit : Feat: Fcm 하위 Batch에 추상클래스 상속
commit : Feat: FcmToken 비즈니스 로직에서 FcmSender 관련 로직 분리 및 batch가 아닌 Fcm 메시지 전송 로직 구현
@Service
public class FcmSenderService {
// 배치 전송 메서드
public void sendFcmWhenMailReceivedBatch(UUID userId, String fromName, String title)
public void sendFcmNotBatch(UUID userId, String fromName, String title)
// 단일 전송 메서드
public void send(FcmNotification fcmNotification)
// 내부 유틸리티 메서드들
private Message buildFcmMessage(FcmNotification fcmNotification)
private void handleSendFailure(FcmNotification fcmNotification, Exception e)
private boolean isInvalidTokenError(Exception e)
}