Skip to content

[DABOM-508] SSE 로직 개선 작업#31

Merged
swthewhite merged 9 commits into
developfrom
fix/DABOM-508
Mar 19, 2026
Merged

[DABOM-508] SSE 로직 개선 작업#31
swthewhite merged 9 commits into
developfrom
fix/DABOM-508

Conversation

@swthewhite
Copy link
Copy Markdown
Contributor

🍀 이슈 & 티켓 넘버


🎯 목적

사용량 데이터의 SSE 실시간 전송 구조를 개선합니다. Kafka 컨슈머와 Redis polling이 동시에 동작하며 충돌하던 문제를 해소하고, 1초 간격 DB 직접 polling 단일 경로로 통일합니다.

📝 변경 사항

  • Kafka USAGE_REALTIME 컨슈머 및 브로드캐스트 전용 설정 삭제
  • PollingService를 Redis polling에서 DB 직접 polling으로 전환 (Family, CustomerQuota 테이블 조회)
  • 하드코딩 값 제거 (totalLimitBytes=20000, customerId=4L 등)
  • SsePublisher에서 미사용 usage push 메서드 및 CAS 맵 제거, pushNotificationEvent()만 유지
  • CustomerQuotaRepository 신규 생성

📂 변경 범위

도메인 controller service repository entity infra global
usagerecord [x]
customer [x]

🖥️ 주요 코드 설명

PollingService DB Polling 전환

// 변경 전: Redis polling + 하드코딩
Optional<Long> latestOpt = familyCacheRepository.findFamilyRemainingBytes(familyId);
long totalLimitBytes = 20000; // 임시 고정
UsageRealtimePayload payload = new UsageRealtimePayload(familyId, 4L, ...);

// 변경 후: DB 직접 조회
Family family = familyRepository.findById(familyId).orElse(null);
long totalQuotaBytes = family.getTotalQuotaBytes();
long usedBytes = family.getUsedBytes();
long remainingBytes = totalQuotaBytes - usedBytes;

// 멤버별 사용량도 DB에서 조회
List<CustomerQuota> quotas = customerQuotaRepository.findByFamilyId(familyId);

💬 리뷰어에게

  • Kafka USAGE_REALTIME 토픽은 더 이상 이 서비스에서 소비하지 않습니다. 토픽 자체의 삭제 여부는 별도 논의가 필요합니다.
  • SSE 이벤트명(usage-updated, usage-updated-by-member)과 페이로드 구조(RealtimeTotalUsageResponse, RealtimeUsageByMemberResponse)는 기존과 동일하여 프론트엔드 변경은 불필요합니다.

📋 체크리스트

기본

  • Merge 대상 브랜치가 올바른가?
  • ./gradlew build가 정상적으로 통과하는가?
  • Spotless / Checkstyle을 통과하는가? (./gradlew spotlessApply checkstyleMain)
  • 전체 변경사항이 500줄을 넘지 않는가?

코드 품질

  • 의존성 방향을 준수하는가? (Controller → Service → Repository → Entity)
  • Setter 없이 비즈니스 메서드로 상태를 변경하는가?
  • @Transactional은 Service에만 선언했는가?

테스트

  • 신규 비즈니스 로직에 대한 단위 테스트를 작성했는가?

📌 참고 사항

  • application.yml에서 spring.kafka.broadcast 설정이 제거되었으므로 환경변수 KAFKA_BROADCAST_GROUP_PREFIX 정리 가능
  • FamilyCacheRepository는 이번 변경으로 PollingService에서 더 이상 사용하지 않으며, 다른 사용처가 없으면 후속 정리 대상

- UsageRecordKafkaConsumer 삭제 (USAGE_REALTIME 토픽 리스너)
- UsageRealtimeBroadcastKafkaConfig 삭제 (브로드캐스트 전용 컨테이너 팩토리)
- application.yml에서 spring.kafka.broadcast 설정 제거
- 사용량 데이터는 PollingService의 DB Polling으로 전환 예정
- PollingService를 Redis polling에서 DB 직접 polling으로 전환
- FamilyRepository에서 totalQuotaBytes, usedBytes 조회
- CustomerQuotaRepository 신규 생성, familyId 기준 멤버별 monthlyUsedBytes 조회
- 하드코딩 제거 (totalLimitBytes=20000, customerId=4L 등)
- SsePublisher에서 pushTotalUsageBytes, pushMemberUsageBytes 및 CAS 맵 제거
- SsePublisher는 pushNotificationEvent만 유지
@github-actions github-actions Bot requested a review from paul0755 March 19, 2026 06:42
@github-actions github-actions Bot added size/L PR size: L chore 기타 변경사항 feat labels Mar 19, 2026
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, 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!

이 PR은 사용량 데이터의 실시간 SSE 전송 구조를 개선하는 것을 목표로 합니다. 기존의 Kafka 컨슈머와 Redis 폴링이 동시에 동작하며 발생하던 충돌 문제를 해결하고, 1초 간격으로 DB를 직접 폴링하는 단일 경로로 시스템을 통합하여 데이터 일관성과 효율성을 높였습니다.

Highlights

  • Kafka 컨슈머 및 브로드캐스트 설정 제거: Kafka USAGE_REALTIME 컨슈머 및 브로드캐스트 관련 설정이 제거되었습니다.
  • PollingService 로직 전환: PollingService가 Redis 폴링 방식에서 DB 직접 폴링 방식으로 전환되었습니다.
  • 하드코딩 값 제거: 코드 내에 하드코딩되어 있던 값들(예: totalLimitBytes, customerId)이 제거되고 동적으로 데이터를 조회하도록 변경되었습니다.
  • SsePublisher 간소화: SsePublisher에서 미사용 메서드와 관련 캐시가 제거되고 pushNotificationEvent()만 남았습니다.
  • CustomerQuotaRepository 신규 생성: CustomerQuota 엔티티를 위한 새로운 JPA 레포지토리 인터페이스가 생성되었습니다.

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

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은 SSE 실시간 사용량 전송 로직을 Kafka와 Redis 폴링 조합에서 DB 직접 폴링 방식으로 개선하는 작업을 담고 있습니다. 전반적으로 코드 구조가 단순화되고 불필요한 의존성이 제거된 점이 좋습니다. 다만, DB 폴링 방식의 성능 최적화를 위한 N+1 문제 해결, 코드 안정성 개선, 그리고 변경된 로직에 대한 테스트 코드 보강이 필요해 보입니다. 관련하여 몇 가지 리뷰 의견을 남겼습니다.

Comment thread src/main/java/com/project/domain/usagerecord/infra/sse/PollingService.java Outdated
- familyRepository.findAllById()로 활성 family 일괄 조회하여 N+1 방지
- customerQuotaRepository.findByFamilyIdIn()으로 변경된 family의 멤버 쿼터 일괄 조회
- findById().orElse(null) 패턴 제거, Map 기반 조회로 전환
- 변경된 familyId만 필터링 후 멤버 쿼터 조회하여 불필요한 쿼리 최소화
- 사용량 변경 시 usage-updated, usage-updated-by-member 이벤트 전송 검증
- 사용량 미변경 시 이벤트 미전송 검증
- Family 미존재 시 이벤트 미전송 검증
@github-actions github-actions Bot added fix 버그 수정 test 테스트 코드 labels Mar 19, 2026
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은 SSE 실시간 사용량 전송 로직을 Kafka 소비 방식에서 DB 폴링 방식으로 개선하는 중요한 변경을 담고 있습니다. 전반적으로 N+1 문제를 고려한 조회 로직 등 잘 작성되었으나, 코드의 명확성과 유지보수성을 높이기 위해 몇 가지 개선점을 제안합니다. 매직 스트링을 상수로 추출하고, 변경 감지 로직을 좀 더 간결하게 다듬으면 좋겠습니다.

Comment thread src/main/java/com/project/domain/usagerecord/infra/sse/PollingService.java Outdated
- 이벤트명 "usage-updated", "usage-updated-by-member"를 상수로 추출
- putIfAbsent + put 중복 호출을 get + put 단일 호출로 간결화
@github-actions github-actions Bot added the refactor 리팩토링 label Mar 19, 2026
- @scheduled(fixedDelay = 1000) 매직넘버를 POLLING_DELAY_MS 상수로 추출
- DB 조회 메서드에 @transactional(readOnly = true) 선언하여 일관된 읽기 보장
- spotlessApply 포매팅 적용
- FamilyCacheRepository 삭제 (DB Polling 전환으로 사용처 없음)
- FamilyCacheDto 삭제 (FamilyCacheRepository 전용)
- RedisKeyGenerator 삭제 (FamilyCacheRepository 전용)
- RedisConfig 삭제 (두 RedisTemplate bean 모두 FamilyCacheRepository 전용)
@github-actions github-actions Bot added size/XL PR size: XL and removed size/L PR size: L labels Mar 19, 2026
- SsePublisher에서 미사용 @slf4j 어노테이션 제거
- CustomerQuotaRepository에서 미사용 findByFamilyId() 메서드 제거
@github-actions
Copy link
Copy Markdown

SonarQube Quality Summary (Community)

Quality Gate FAILED

Branch: fix/DABOM-508
Compared to: default branch

Issues

  • 🐞 Bugs: 8
  • 🔐 Vulnerabilities: 0
  • 📎 Code Smells: 92

Measures

  • Coverage: N/A (커버리지 제외 중)
  • Duplication: 0%

🔗 Dashboard: https://sonarqube.swthewhite.store/dashboard?id=dabom-api-notification

Generated automatically by GitHub Actions.

- 모든 인자가 구체 값인 verify()에서 eq() 래핑 제거
- any()와 혼용되는 곳은 Mockito 규칙상 eq() 유지
@github-actions
Copy link
Copy Markdown

SonarQube Quality Summary (Community)

Quality Gate PASSED

Branch: fix/DABOM-508
Compared to: default branch

Issues

  • 🐞 Bugs: 8
  • 🔐 Vulnerabilities: 0
  • 📎 Code Smells: 92

Measures

  • Coverage: N/A (커버리지 제외 중)
  • Duplication: 0%

🔗 Dashboard: https://sonarqube.swthewhite.store/dashboard?id=dabom-api-notification

Generated automatically by GitHub Actions.

Copy link
Copy Markdown
Member

@k0081915 k0081915 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 cf0f581 into develop Mar 19, 2026
9 checks passed
@swthewhite swthewhite deleted the fix/DABOM-508 branch March 19, 2026 09:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore 기타 변경사항 feat fix 버그 수정 refactor 리팩토링 size/XL PR size: XL test 테스트 코드

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DABOM-508] SSE 로직 개선 작업

2 participants