-
Notifications
You must be signed in to change notification settings - Fork 4
✨ feat: Email 메시지 재시도 및 DLQ 처리 로직 구현 #499
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
CodeVac513
wants to merge
45
commits into
main
Choose a base branch
from
feat/email-retry-dlq
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
🔨 테스크
이메일 전송에 실패했을 때, 로그 외에 어떻게 추적하고 처리할 수 있을까?
제가 생각했던 내용은 3가지입니다.
결정: 옵션 3 (DLQ 기반 접근) 선택
실시간성이 낮고, 데이터 변경이 적기 때문에 DB 조회 오버헤드가 적은 Fat event를 선택했습니다.
그리고 Worker는 이메일 전송만 담당하는 단일 책임을 가져야 합니다.
제가 고민했던 내용은
실패 추적 / 재시도를 위해 DB를 도입하면 Fat event의 이점이 사라지는가?였습니다.3가지 방법 중, DLQ 기반의 3번 접근이 가장 적합하다고 생각했습니다.
이유는 다음과 같습니다:
Permanent Error와 Transient Error
Permanent Error는 쉽게 말해서email 데이터가 누락되었거나, 문자열에 공백이 껴서 파싱이 안되는 것 등의 재시도를 통해서 해결할 수 없는 에러를 의미합니다.
Trasient Error는 트래픽이 갑자기 몰리거나 내부 로직의 버그 등의 요인으로 SMTP 서버가 갑자기 다운된 상태를 가정할 수 있습니다. 이는 1초, 10초, 길면 수 시간 뒤에 요청하면 해결될 수도 있습니다.
Permanent Error는 크게 두 가지 범주로 나뉠 수 있습니다:
이런 Permanent Error는 발생한 에러를 처리하는 것보다 Producer에서 사전에 방지하는 것이 더 좋습니다.
현재 구현에서는 Producer가 TypeORM의 Entity를 사용하고 검증된 데이터만 발행합니다.
이에 따라, Permanent Error의 발생 가능성이 매우 낮습니다.
만약 발생한다면 DLQ로 모두 보내고, 향후 필요하다면 자동 복구 로직을 추가할 예정입니다.
Trasient Error는 재시도 로직만 잘 생각하면 됩니다.
외부 서비스인 SMTP 서버에 의존하기에 네트워크나 SMTP 서버의 상태에 따라 결과가 달라질 수 있습니다.
재시도 로직은 어떻게 구현할까?
앞서 설명했던 에러 중 Trasient Error에 집중을 하여, 재시도 로직을 구성해야 합니다.
몇 초 간격으로, 어느 구현 레벨에서 재시도를 할 것인가?가 주요 주제입니다.백오프 전략
백오프는 오류 발생 시 재시도를 일시적으로 줄이거나 지연시키는 전략을 말하는데, 쉽게 3가지를 생각할 수 있습니다.
구현 레벨 비교
애플리케이션 레벨
RabbitMQ Delayed Message 플러그인 사용
지연 메시지가 한 노드에만 저장되면 대기 중인 모든 메시지가 손실되는 위험이 발생할 수 있음.
(공식 문서에서는 최소 3개 이상의 노드가 띄워진 클러스터에서 사용하는 것을 권장함.)
RabbitMQ 레벨에서 재시도 및 대기를 위한 queue를 만들어 사용하기
'x-message-ttl'이라는 헤더를 통해서 메시지에 대해 소비 기한을 놔두고, TTL이 만료되면 consumer가 리스닝하고 있는 큐로 재발행함
'x-retry-count'라는 consumer가 설정한 재시도 횟수를 저장하는 헤더를 하나 만들어둬야 함 (공식 지원 헤더 아님)
나중에 retry count를 확인해서, 사용자가 설정한 한계를 넘어서면 DLQ로 던지는 형식
정리: Wait Queue는 단순 시간 지연 역할만 하고, 모든 로직은 개발자가 consumer에서 컨트롤함.
장점
단점
이렇게 3가지 방안을 비교해서 마지막 방법을 선택했습니다.
초기 설정에서만 queue를 여러 개 사용하면 되고, 현재 이메일 전송 조건 등의 로직이 단순해서 관리가 복잡하지는 않습니다.
추후에 서비스 기능이 확장되고 트래픽이 커지면, 클러스터링을 통해서 플러그인 도입으로 이관하는 것이 더 좋을 것이라 판단했습니다.
📋 작업 내용
📷 스크린 샷(선택 사항)
동작 화면 첨부