UPLUS-134 알림 이벤트 Consumer 기능 구현 (초안)#2
Conversation
Summary of ChangesHello @starboxxxx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 Pull Request는 사용량 알림 이벤트를 처리하기 위한 Kafka 컨슈머의 초기 구현을 도입합니다. 주요 목표는 들어오는 알림 메시지를 처리하기 위한 견고하고 확장 가능한 시스템을 구축하는 것으로, 중복 제거 및 적절한 포맷팅을 포함하며, 컨슈머가 특정 배포 환경에서만 활성화되도록 합니다. 이 변경사항은 Kafka 통합을 크게 리팩토링하여 향상된 보안 및 메시지 처리 기능을 갖춘 보다 프로덕션에 적합한 설정으로 나아갑니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
이번 PR은 알림 이벤트 처리를 위한 Kafka 컨슈머 기능을 구현한 것으로 보입니다. 전반적으로 프로필 기반으로 컨슈머를 활성화하고, Redis를 이용해 이벤트 중복 처리를 방지하는 등 좋은 시도들이 보입니다. 다만, 몇 가지 개선점을 제안합니다. 가장 중요한 것은 예외 발생 시 메시지 처리 정책입니다. 현재는 메시지가 유실될 위험이 있어 재시도나 DLQ 패턴 도입을 검토해야 합니다. 또한, 하드코딩된 값들을 상수로 추출하고, 파일 로깅 방식을 개선하여 코드의 안정성과 유지보수성을 높이는 방향을 제안했습니다. 자세한 내용은 각 파일에 남긴 코멘트를 참고해주세요.
| } catch (Exception e) { | ||
| log.error("[CONSUME FAIL]", e); | ||
| ack.acknowledge(); // 지금 구조상 스킵이 맞음 | ||
| } |
There was a problem hiding this comment.
예외 발생 시 메시지를 ack 처리하면 해당 메시지는 유실되어 알림이 누락될 수 있습니다. 이는 데이터 정합성에 심각한 문제를 야기할 수 있습니다.
일시적인 오류(예: DB 접속 불가)의 경우 재시도를 통해 문제를 해결할 수 있어야 하며, 영구적인 오류(예: 메시지 포맷 오류)의 경우 메시지를 Dead Letter Queue(DLQ)로 보내 나중에 분석할 수 있도록 하는 것이 좋습니다.
ack.acknowledge()를 호출하는 대신, 예외를 다시 던지거나 SeekToCurrentErrorHandler와 같은 스프링 카프카의 오류 처리 메커니즘을 활용하여 재시도 및 DLQ 전송을 구현하는 것을 강력히 권장합니다.
|
|
||
| public boolean tryAcquire(String eventId) { | ||
| Boolean success = | ||
| redisTemplate.opsForValue().setIfAbsent("notification:event:" + eventId, "1", TTL); |
There was a problem hiding this comment.
Redis 키의 접두사 "notification:event:" 와 값 "1" 이 하드코딩되어 있습니다. 가독성과 유지보수성을 높이기 위해 private static final 상수로 추출하는 것을 권장합니다.
예시:
private static final String DEDUP_KEY_PREFIX = "notification:event:";
private static final String DEDUP_KEY_VALUE = "1";
// ...
redisTemplate.opsForValue().setIfAbsent(DEDUP_KEY_PREFIX + eventId, DEDUP_KEY_VALUE, TTL);| private static final Path LOG_PATH = Path.of("logs/notification-preview.log"); | ||
|
|
||
| public static void write(String content) { | ||
| try { | ||
| Files.createDirectories(LOG_PATH.getParent()); | ||
|
|
||
| Files.writeString( | ||
| LOG_PATH, | ||
| """ | ||
| =============================== | ||
| %s | ||
| %s | ||
| =============================== | ||
|
|
||
| """ | ||
| .formatted(LocalDateTime.now(), content), | ||
| StandardOpenOption.CREATE, | ||
| StandardOpenOption.WRITE, | ||
| StandardOpenOption.APPEND); | ||
| } catch (IOException e) { | ||
| log.error("Failed to write notification preview file", e); | ||
| } | ||
| } |
There was a problem hiding this comment.
SendNotificationLogger 구현에 대해 몇 가지 개선점을 제안합니다.
- 하드코딩된 경로: 로그 파일 경로(
logs/notification-preview.log)가 하드코딩되어 있습니다. 환경에 따라 경로를 변경할 수 있도록application.yml에서 설정을 주입받는 것이 더 유연합니다. - 직접 파일 쓰기:
Files.writeString을 사용하는 방식은 초안에서는 괜찮지만, 운영 환경에서는 스레드 안전성, 성능, 로그 관리(로테이션 등) 측면에서 불리합니다.
운영 환경을 고려하여, 이 클래스를 Spring Bean으로 만들고 Logback/Log4j2 같은 로깅 프레임워크의 FileAppender를 사용하도록 리팩토링하는 것을 권장합니다. 경로 설정도 외부에서 주입받도록 변경하면 더욱 견고하고 유연한 코드가 될 것입니다.
| } | ||
|
|
||
| private String formatGb(long mb) { | ||
| return String.format("%.2f", mb / 1024.0); |
SonarQube Quality Summary (Community)✅ Quality Gate PASSED Branch: Issues
Measures
🔗 Dashboard: https://sonarqube.swthewhite.store/dashboard?id=api-message&branch=feat/UPLUS-134 Generated automatically by GitHub Actions. |
🍀 이슈 번호
✅ 작업 사항
UPLUS-134 알림 이벤트 Consumer 기능 구현 (초안)
📋 체크리스트
⌨ 기타