[FEATURE] RabbitMQ 연동#124
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughSMTP 기반 메일 발송을 제거하고 RabbitMQ 메시지 발행 방식으로 전환했습니다. RabbitMQ 실행·배포 설정, 메일 메시지 계약, 아웃박스 확인 처리, 인증 메일 및 환불 알림 데이터가 변경되었습니다. ChangesRabbitMQ 메일 알림 파이프라인
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant EmailVerificationMailer
participant MailPublisher
participant RabbitMQ
EmailVerificationMailer->>MailPublisher: MailMessage 발행
MailPublisher->>RabbitMQ: 메일 메시지 전송
RabbitMQ-->>MailPublisher: confirm 또는 returns 결과
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/main/java/ditda/backend/global/notification/NotificationOutboxScheduler.java (1)
40-58: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win발행 확인(Publisher Confirm) 대기를 일괄 처리(Batching)하여 성능을 개선할 것을 권장합니다.
반복문 내에서 매 메시지마다
.get(5, TimeUnit.SECONDS)를 호출하여 동기적으로 대기하면, 한 번에 처리할 메시지 수가 많거나 브로커 응답이 지연될 경우 스케줄러 스레드가 지나치게 오랫동안 블로킹될 수 있습니다. (예: 최대 100건 * 5초 = 최대 500초 블로킹)먼저 반복문을 돌며 메시지를 모두 발행하여 반환된
Future를 리스트로 수집한 후, 다음 루프에서 한꺼번에 결과를 대기하도록 리팩토링하면 발송 전체 처리량(Throughput)을 크게 향상시킬 수 있습니다.💡 리팩토링 예시
// 발행과 결과 확인을 두 번의 루프로 분리하여 대기 시간을 최적화합니다. List<Map.Entry<NotificationOutbox, CorrelationData>> pendingConfirms = new ArrayList<>(); for (NotificationOutbox outbox : pendingAlerts) { try { MailMessage message = new MailMessage( outbox.getType().name(), outbox.getRecipientEmail(), outbox.getTemplateVariables() ); CorrelationData correlationData = new CorrelationData(outbox.getId().toString()); mailPublisher.publish(message, correlationData); pendingConfirms.add(new java.util.AbstractMap.SimpleEntry<>(outbox, correlationData)); } catch (Exception e) { log.error("아웃박스 알림 발행 중 에러 발생. outboxId={}", outbox.getId(), e); outbox.recordRetry(e.getMessage()); outboxRepository.save(outbox); } } for (Map.Entry<NotificationOutbox, CorrelationData> entry : pendingConfirms) { NotificationOutbox outbox = entry.getKey(); CorrelationData correlationData = entry.getValue(); try { CorrelationData.Confirm confirm = correlationData.getFuture().get(5, TimeUnit.SECONDS); if (confirm.ack()) { outbox.markSent(); } else { outbox.recordRetry("Broker Not Confirmed"); } outboxRepository.save(outbox); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.warn("아웃박스 알림 발행 인터럽트. outboxId={}", outbox.getId(), e); break; } catch (Exception e) { log.error("아웃박스 알림 발행 실패. outboxId={}", outbox.getId(), e); outbox.recordRetry(e.getMessage()); outboxRepository.save(outbox); } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/ditda/backend/global/notification/NotificationOutboxScheduler.java` around lines 40 - 58, Refactor the notification processing loop around mailPublisher.publish and CorrelationData so all pending messages are published first and their correlation futures are collected, then await confirmations in a separate loop. Preserve the existing ack handling, retry recording, and outboxRepository.save behavior while preventing each message from blocking publication of subsequent messages.docker-compose.prod.yaml (1)
68-70: 📐 Maintainability & Code Quality | 🔵 Trivial운영 팁: RabbitMQ 계정 정보 변경 시 주의사항
RABBITMQ_DEFAULT_USER와RABBITMQ_DEFAULT_PASS환경 변수는 데이터 볼륨(rabbitmq-data)이 비어 있는 최초 컨테이너 실행 시에만 적용됩니다.
이후 운영 환경의 파라미터 스토어(SSM)에서 비밀번호를 변경하고 재배포하더라도 기존 컨테이너의 비밀번호는 갱신되지 않으므로, 비밀번호 변경이 필요한 경우rabbitmqctl change_password명령어를 직접 사용하거나 볼륨을 초기화해야 합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docker-compose.prod.yaml` around lines 68 - 70, Document that RABBITMQ_DEFAULT_USER and RABBITMQ_DEFAULT_PASS are applied only when the rabbitmq-data volume is initialized, and do not update existing credentials on redeploy. Include the required credential-rotation action using rabbitmqctl change_password or volume reinitialization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/resources/db/migration/V20260715212830__add_type_to_notification_outboxes.sql`:
- Around line 8-15: Update the migration to add notification_type as nullable
first, backfill existing rows from template_name, validate that all rows have a
valid type, then enforce NOT NULL. Do not drop subject or template_name in this
migration; defer those column removals to a separate migration after the
rollback window for the previous deployment has ended.
---
Nitpick comments:
In `@docker-compose.prod.yaml`:
- Around line 68-70: Document that RABBITMQ_DEFAULT_USER and
RABBITMQ_DEFAULT_PASS are applied only when the rabbitmq-data volume is
initialized, and do not update existing credentials on redeploy. Include the
required credential-rotation action using rabbitmqctl change_password or volume
reinitialization.
In
`@src/main/java/ditda/backend/global/notification/NotificationOutboxScheduler.java`:
- Around line 40-58: Refactor the notification processing loop around
mailPublisher.publish and CorrelationData so all pending messages are published
first and their correlation futures are collected, then await confirmations in a
separate loop. Preserve the existing ack handling, retry recording, and
outboxRepository.save behavior while preventing each message from blocking
publication of subsequent messages.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 24ad8a5a-e61a-4986-b291-1996763cb7df
⛔ Files ignored due to path filters (1)
src/main/resources/email-images/logo.pngis excluded by!**/*.png
📒 Files selected for processing (40)
.env.examplebuild.gradledocker-compose.prod.yamldocker-compose.yamlscripts/deploy.shsrc/main/java/ditda/backend/domain/auth/exception/AuthErrorCode.javasrc/main/java/ditda/backend/domain/auth/notification/EmailVerificationMailer.javasrc/main/java/ditda/backend/domain/commission/core/notification/ApplicationDeadlineClosedNotifier.javasrc/main/java/ditda/backend/domain/commission/core/notification/FirstDraftDeadlineClosedNotifier.javasrc/main/java/ditda/backend/global/config/RabbitConfig.javasrc/main/java/ditda/backend/global/notification/EmailSender.javasrc/main/java/ditda/backend/global/notification/MailMessage.javasrc/main/java/ditda/backend/global/notification/MailPublisher.javasrc/main/java/ditda/backend/global/notification/MailRabbitConfig.javasrc/main/java/ditda/backend/global/notification/NotificationOutbox.javasrc/main/java/ditda/backend/global/notification/NotificationOutboxScheduler.javasrc/main/java/ditda/backend/global/notification/NotificationType.javasrc/main/resources/application.yamlsrc/main/resources/db/migration/V20260715212830__add_type_to_notification_outboxes.sqlsrc/main/resources/templates/email/admin-payout-request.htmlsrc/main/resources/templates/email/admin-refund-request.htmlsrc/main/resources/templates/email/commission-cancelled.htmlsrc/main/resources/templates/email/commission-finalized-designer.htmlsrc/main/resources/templates/email/commission-finalized-instructor.htmlsrc/main/resources/templates/email/commission-matched-designer.htmlsrc/main/resources/templates/email/commission-matched-instructor.htmlsrc/main/resources/templates/email/commission-shortfall-instructor.htmlsrc/main/resources/templates/email/deposit-notification.htmlsrc/main/resources/templates/email/designer-signup-notification.htmlsrc/main/resources/templates/email/final-cancelled-designer.htmlsrc/main/resources/templates/email/final-cancelled-instructor.htmlsrc/main/resources/templates/email/first-draft-all-submitted-instructor.htmlsrc/main/resources/templates/email/first-draft-missed-designer.htmlsrc/main/resources/templates/email/first-draft-rejected-designer.htmlsrc/main/resources/templates/email/first-draft-selected-designer.htmlsrc/main/resources/templates/email/first-draft-shortfall-instructor.htmlsrc/main/resources/templates/email/first-draft-zero-instructor.htmlsrc/main/resources/templates/email/revision-requested-designer.htmlsrc/main/resources/templates/email/revision-submitted-instructor.htmlsrc/main/resources/templates/email/verification-code.html
💤 Files with no reviewable changes (22)
- src/main/resources/templates/email/commission-matched-instructor.html
- src/main/resources/templates/email/commission-matched-designer.html
- src/main/resources/templates/email/final-cancelled-instructor.html
- src/main/resources/templates/email/first-draft-all-submitted-instructor.html
- src/main/resources/templates/email/final-cancelled-designer.html
- src/main/resources/templates/email/deposit-notification.html
- src/main/resources/templates/email/first-draft-missed-designer.html
- src/main/resources/templates/email/admin-payout-request.html
- src/main/resources/templates/email/revision-requested-designer.html
- src/main/resources/templates/email/first-draft-shortfall-instructor.html
- src/main/resources/templates/email/commission-cancelled.html
- src/main/resources/templates/email/verification-code.html
- src/main/resources/templates/email/first-draft-selected-designer.html
- src/main/resources/templates/email/commission-finalized-instructor.html
- src/main/resources/templates/email/commission-finalized-designer.html
- src/main/resources/templates/email/first-draft-zero-instructor.html
- src/main/resources/templates/email/admin-refund-request.html
- src/main/resources/templates/email/designer-signup-notification.html
- src/main/resources/templates/email/first-draft-rejected-designer.html
- src/main/resources/templates/email/revision-submitted-instructor.html
- src/main/java/ditda/backend/global/notification/EmailSender.java
- src/main/resources/templates/email/commission-shortfall-instructor.html
Jong0128
left a comment
There was a problem hiding this comment.
수고하셨습니다!! 😄
아래 코멘트 확인 한번만 부탁드립니다!
Jong0128
left a comment
There was a problem hiding this comment.
수고하셨습니다!
바로 merge해도 좋을꺼같습니다!! 👍
🚀 Related issue
Closes #122
#️⃣ Summary
🔧 Changes
docker-compose local/prod) 및 배포 환경변수(RABBITMQ_*) 구성subject/template저장 ->NotificationType(enum)저장으로 전환AmqpException-> 도메인 예외 변환NotificationOutboxScheduler에서 직접 발송 -> Outbox 릴레이 발행으로 변경📸 Test Evidence
💬 Reviewer Notes
실제 발송 로직은 별도 레포 Ditda-Notification-Worker에 구현되어 있고, 같은 EC2·Docker 네트워크(
ditda-net)에서 구동됩니다.현재 단계에서는 서버 분리는 과하다고 판단해, 관심사/의존성만 분리했습니다.
환경변수에 변경사항들이 있어서 노션 참고 부탁드립니다.
notification_outboxes에 subject/template_name 대신 notification_type을 활용해 제목/템플릿을 판단하도록 했습니다.Summary by CodeRabbit
새로운 기능
개선 사항
변경 사항