Refactor/294 : 전략 패턴 기반 메일 발송 방식 변경에 RateLimiter 설정 변경 추가#339
Conversation
Walkthrough이 변경사항은 메일 발송 전략 패턴에서 RateLimiter(버킷) 설정을 각 전략에 내장하고, RedisStreamReader가 MailSenderContext를 통해 동적으로 버킷을 조회하도록 리팩토링하였습니다. 기존 RateLimiterConfig 및 관련 프로퍼티는 제거되었으며, 각 전략 클래스에 버킷이 직접 구현되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Reader as RedisStreamReader
participant Context as MailSenderContext
participant Strategy as MailSenderStrategy
Reader->>Context: getBucket(strategyKey)
Context->>Strategy: getBucket()
Strategy-->>Context: Bucket
Context-->>Reader: Bucket
Note over Reader: Reader uses Bucket for rate limiting
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes(해당 사항 없음) Possibly related PRs
Suggested reviewers
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
cs25-batch/src/main/java/com/example/cs25batch/sender/SesMailSenderStrategy.java (1)
16-22: RateLimiter 설정이 적절하지만 설정 외부화를 고려해보세요.SES 전략의 버킷 설정(용량: 14, 재충전: 7개/500ms)이 합리적입니다. 하지만 하드코딩된 값들을 프로퍼티로 외부화하면 환경별 조정이 용이해집니다.
다음과 같이 프로퍼티 기반 설정을 고려해보세요:
+@Value("${mail.ses.bucket.capacity:14}") +private int bucketCapacity; + +@Value("${mail.ses.bucket.refill.tokens:7}") +private int refillTokens; + +@Value("${mail.ses.bucket.refill.period:500}") +private long refillPeriodMs; -private final Bucket bucket = Bucket.builder() - .addLimit(limit -> - limit - .capacity(14) - .refillIntervally(7, Duration.ofMillis(500)) - ) - .build(); +private final Bucket bucket = Bucket.builder() + .addLimit(limit -> + limit + .capacity(bucketCapacity) + .refillIntervally(refillTokens, Duration.ofMillis(refillPeriodMs)) + ) + .build();cs25-batch/src/main/java/com/example/cs25batch/batch/component/reader/RedisStreamReader.java (1)
40-40: 버킷 조회 성능 최적화를 고려하세요.
read()메서드에서 매번 버킷을 조회하는 것보다 초기화 시점에 캐싱하는 것이 성능상 유리합니다.다음과 같이 버킷을 캐싱하는 것을 고려해보세요:
+private Bucket cachedBucket; + +@PostConstruct +private void initializeBucket() { + this.cachedBucket = mailSenderContext.getBucket(strategyKey); +} @Override public Map<String, String> read() throws InterruptedException { - Bucket bucket = mailSenderContext.getBucket(strategyKey); + // cachedBucket 사용 - while (!bucket.tryConsume(1)) { + while (!cachedBucket.tryConsume(1)) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
cs25-batch/src/main/java/com/example/cs25batch/batch/component/reader/RedisStreamReader.java(3 hunks)cs25-batch/src/main/java/com/example/cs25batch/config/RateLimiterConfig.java(0 hunks)cs25-batch/src/main/java/com/example/cs25batch/sender/JavaMailSenderStrategy.java(1 hunks)cs25-batch/src/main/java/com/example/cs25batch/sender/MailSenderStrategy.java(1 hunks)cs25-batch/src/main/java/com/example/cs25batch/sender/SesMailSenderStrategy.java(1 hunks)cs25-batch/src/main/java/com/example/cs25batch/sender/context/MailSenderContext.java(2 hunks)cs25-batch/src/main/resources/application.properties(0 hunks)
💤 Files with no reviewable changes (2)
- cs25-batch/src/main/resources/application.properties
- cs25-batch/src/main/java/com/example/cs25batch/config/RateLimiterConfig.java
🧰 Additional context used
🧠 Learnings (1)
cs25-batch/src/main/java/com/example/cs25batch/sender/JavaMailSenderStrategy.java (2)
Learnt from: crocusia
PR: #141
File: cs25-batch/src/main/java/com/example/cs25batch/batch/jobs/DailyMailSendJob.java:187-195
Timestamp: 2025-06-23T01:34:30.742Z
Learning: DailyMailSendJob에서 taskExecutor bean은 mailConsumerWithAsyncStep에서만 사용되므로, ThreadShuttingJobListener로 해당 작업 완료 후 executor를 종료해도 다른 배치 작업들에 영향을 주지 않습니다.
Learnt from: crocusia
PR: #191
File: cs25-batch/src/main/java/com/example/cs25batch/aop/MailLogAspect.java:60-60
Timestamp: 2025-06-27T09:00:50.236Z
Learning: MailLogAspect에서 mailLogRepository.flush() 호출은 배치 처리의 청크 단위 트랜잭션과 비동기 처리 환경에서 MailLog의 즉시 영속화가 필요해서 추가된 것입니다. 재시도 로직이 실패한 메일 로그에 즉시 접근해야 하는 요구사항 때문에 필수적입니다.
🔇 Additional comments (9)
cs25-batch/src/main/java/com/example/cs25batch/sender/MailSenderStrategy.java (1)
4-4: 전략 패턴 인터페이스 확장이 적절합니다.
getBucket()메서드 추가로 각 전략이 자체 RateLimiter를 관리할 수 있게 되어 설정의 응집성이 향상되었습니다.Also applies to: 9-9
cs25-batch/src/main/java/com/example/cs25batch/sender/SesMailSenderStrategy.java (1)
29-32: getBucket() 구현이 올바릅니다.전략 인터페이스를 정확히 구현하여 버킷 인스턴스를 반환합니다.
cs25-batch/src/main/java/com/example/cs25batch/sender/JavaMailSenderStrategy.java (1)
29-32: getBucket() 구현이 올바릅니다.전략 인터페이스를 정확히 구현합니다.
cs25-batch/src/main/java/com/example/cs25batch/sender/context/MailSenderContext.java (3)
17-19: 메서드 리팩토링이 적절합니다.공통 전략 검증 로직을
getValidStrategy로 추출하여 코드 중복을 제거했습니다.
21-24: 새로운 getBucket 메서드가 올바르게 구현되었습니다.전략별 버킷을 동적으로 조회할 수 있게 하여 RateLimiter 설정의 유연성이 향상되었습니다.
26-32: 검증 로직 중앙화가 우수합니다.전략 검증과 오류 처리를 한 곳에서 관리하여 일관성과 유지보수성이 개선되었습니다.
cs25-batch/src/main/java/com/example/cs25batch/batch/component/reader/RedisStreamReader.java (3)
31-32: 전략 키 설정이 적절합니다.기본값 제공으로 안전성을 보장하면서 설정 가능한 전략 선택을 지원합니다.
34-35: 의존성 주입 방식 변경이 적절합니다.@requiredargsconstructor 사용으로 생성자 코드가 간소화되었습니다.
40-40: 잘못된 strategyKey 처리 현황 및 개선 제안현재 MailSenderContext#getValidStrategy 메서드에서 유효하지 않은
strategyKey사용 시
IllegalArgumentException("메일 전략이 존재하지 않습니다: " + strategyKey)를 던져 즉시 실패(fail-fast)하도록 구현되어 있습니다.추가로 배치 시작 단계에서 빠르게 검증하려면 다음을 고려해보세요:
- RedisStreamReader(또는 MailConsumerProcessor) 클래스에
@PostConstruct메서드를 추가하여
mailSenderContext.getBucket(strategyKey)호출로 애플리케이션 구동 시점에 유효성 확인- invalid key 입력 시 예외 발생 여부를 검증하는 단위 테스트 추가
🔎 작업 내용
🛠️ 변경 사항
🧯 해결해야 할 문제
(둘 다 동기, 비동기의 필요성 정도는 다르지만 사용은 모두 가능하다는 애매함)
close #294
Summary by CodeRabbit
신규 기능
리팩터링
환경설정 변경