Skip to content

UPLUS-134 알림 이벤트 Consumer 기능 구현 (초안)#2

Merged
swthewhite merged 2 commits into
developfrom
feat/UPLUS-134
Jan 23, 2026
Merged

UPLUS-134 알림 이벤트 Consumer 기능 구현 (초안)#2
swthewhite merged 2 commits into
developfrom
feat/UPLUS-134

Conversation

@starboxxxx
Copy link
Copy Markdown
Contributor

🍀 이슈 번호

  • UPLUS-134

✅ 작업 사항

UPLUS-134 알림 이벤트 Consumer 기능 구현 (초안)


📋 체크리스트

  • 코드가 정상적으로 빌드됩니다.
  • 관련 테스트 코드를 작성했습니다.
  • 기존 테스트가 모두 통과합니다.
  • 코드 스타일(Spotless, Checkstyle)을 준수합니다.

⌨ 기타

@starboxxxx starboxxxx self-assigned this Jan 23, 2026
@starboxxxx starboxxxx added the feat 새로운 기능 label Jan 23, 2026
@github-actions github-actions Bot added the size/L PR size: L label Jan 23, 2026
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @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

  • Kafka 컨슈머 기능 구현: 사용량 알림 이벤트를 처리하기 위한 새로운 Kafka 컨슈머(NotificationConsumer)가 notification-usage 토픽을 구독하도록 구현되었습니다.
  • 이벤트 중복 제거 메커니즘 도입: Redis를 활용한 NotificationSendDedupService를 통해 알림 이벤트의 중복 처리를 방지하는 메커니즘이 추가되어, 이벤트 처리의 멱등성을 보장합니다.
  • 알림 메시지 포맷 및 로깅: 새로운 UsageNotificationMessageFormatterSendNotificationLogger가 도입되어, 수신된 이벤트를 사용자 친화적인 메시지로 포맷하고 이를 로그 파일에 기록하여 알림 미리보기를 가능하게 합니다.
  • 프로파일 기반 컨슈머 활성화: Kafka 리스너는 notification-worker 스프링 프로파일이 활성화된 경우에만 자동으로 시작되도록 설정되어, 배포 환경에 따른 유연한 제어가 가능합니다.
  • Kafka 설정 업데이트: application.yml 파일의 Kafka 설정이 SASL_SSL 보안, 상세한 프로듀서/컨슈머 속성, 새로운 컨슈머 그룹 ID 등을 포함하여 전반적으로 업데이트되었습니다.
  • JPA DDL 자동 업데이트 비활성화: spring.jpa.hibernate.ddl-auto 설정이 update에서 none으로 변경되어, 데이터베이스 스키마 관리가 외부 또는 수동으로 이루어짐을 나타냅니다.

🧠 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 Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이번 PR은 알림 이벤트 처리를 위한 Kafka 컨슈머 기능을 구현한 것으로 보입니다. 전반적으로 프로필 기반으로 컨슈머를 활성화하고, Redis를 이용해 이벤트 중복 처리를 방지하는 등 좋은 시도들이 보입니다. 다만, 몇 가지 개선점을 제안합니다. 가장 중요한 것은 예외 발생 시 메시지 처리 정책입니다. 현재는 메시지가 유실될 위험이 있어 재시도나 DLQ 패턴 도입을 검토해야 합니다. 또한, 하드코딩된 값들을 상수로 추출하고, 파일 로깅 방식을 개선하여 코드의 안정성과 유지보수성을 높이는 방향을 제안했습니다. 자세한 내용은 각 파일에 남긴 코멘트를 참고해주세요.

Comment on lines +51 to 54
} catch (Exception e) {
log.error("[CONSUME FAIL]", e);
ack.acknowledge(); // 지금 구조상 스킵이 맞음
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

예외 발생 시 메시지를 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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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);

Comment on lines +14 to +36
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);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

SendNotificationLogger 구현에 대해 몇 가지 개선점을 제안합니다.

  1. 하드코딩된 경로: 로그 파일 경로(logs/notification-preview.log)가 하드코딩되어 있습니다. 환경에 따라 경로를 변경할 수 있도록 application.yml에서 설정을 주입받는 것이 더 유연합니다.
  2. 직접 파일 쓰기: Files.writeString을 사용하는 방식은 초안에서는 괜찮지만, 운영 환경에서는 스레드 안전성, 성능, 로그 관리(로테이션 등) 측면에서 불리합니다.

운영 환경을 고려하여, 이 클래스를 Spring Bean으로 만들고 Logback/Log4j2 같은 로깅 프레임워크의 FileAppender를 사용하도록 리팩토링하는 것을 권장합니다. 경로 설정도 외부에서 주입받도록 변경하면 더욱 견고하고 유연한 코드가 될 것입니다.

}

private String formatGb(long mb) {
return String.format("%.2f", mb / 1024.0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

MB를 GB로 변환할 때 사용된 1024.0은 '매직 넘버'입니다. 코드의 가독성을 높이고 의도를 명확히 하기 위해 private static final double MB_PER_GB = 1024.0; 와 같이 상수로 정의하여 사용하는 것을 권장합니다.

@github-actions
Copy link
Copy Markdown

SonarQube Quality Summary (Community)

Quality Gate PASSED

Branch: feat/UPLUS-134
Compared to: default branch

Issues

  • 🐞 Bugs: 0
  • 🔐 Vulnerabilities: 2
  • 📎 Code Smells: 40

Measures

  • Coverage: 0%
  • Duplication: 0%

🔗 Dashboard: https://sonarqube.swthewhite.store/dashboard?id=api-message&branch=feat/UPLUS-134

Generated automatically by GitHub Actions.

Copy link
Copy Markdown
Contributor

@swthewhite swthewhite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다

@swthewhite swthewhite merged commit b6840e7 into develop Jan 23, 2026
11 checks passed
@swthewhite swthewhite deleted the feat/UPLUS-134 branch January 23, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 새로운 기능 size/L PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants