Conversation
- 이미 complete된 emitter에 send를 시도하면 IllegalStateException이 발생할 수 있어 알림 전송 자체보다 끊어진 연결 정리를 우선하도록 변경 - IOException만 completeWithError로 마무리하고 IllegalStateException은 emitter 제거로만 끝내 이미 종료된 emitter를 다시 종료하면서 예외가 전파되는 상황을 막음 - 완료된 emitter가 맵에 남아 있어도 예외 없이 정리되는 단위 테스트를 추가해 재연 경로를 고정하고 회귀를 방지
📝 WalkthroughWalkthrough
Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
🧪 JaCoCo Coverage Report (Changed Files)Summary
Coverage by File
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/gg/agit/konect/domain/notification/service/NotificationInboxSseService.java`:
- Around line 53-55: The call to emitter.completeWithError(ioException) in
NotificationInboxSseService can itself throw IllegalStateException during race
conditions (emitter already completed); wrap the completeWithError(ioException)
invocation in its own try-catch that catches IllegalStateException and only logs
the occurrence (do not rethrow), so the send error handling does not propagate a
second exception; locate the call to emitter.completeWithError in the method
that handles IOException and add the separate try {
emitter.completeWithError(ioException); } catch (IllegalStateException e) { /*
log and swallow */ } around it.
In
`@src/test/java/gg/agit/konect/unit/domain/notification/service/NotificationInboxSseServiceTest.java`:
- Around line 116-123: The test is non-deterministic because it calls
notificationInboxSseService.subscribe(1).complete() then re-inserts the emitter
into emitters(), risking the completion callback to remove the entry before
send(1, ...) runs; change the setup to deterministically place a completed
emitter into the service map (e.g., create a new SseEmitter instance, call
complete() on it, and directly put that instance into emitters()) or use a test
double for SseEmitter that is already completed so that
notificationInboxSseService.send(1, response) always exercises the
IllegalStateException/cleanup branch; update NotificationInboxSseServiceTest to
stop relying on subscribe(...) side effects and instead inject the completed
emitter into emitters() before calling send().
🪄 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.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3f33fbe6-4df8-49bd-8381-1d02a9df592d
📒 Files selected for processing (2)
src/main/java/gg/agit/konect/domain/notification/service/NotificationInboxSseService.javasrc/test/java/gg/agit/konect/unit/domain/notification/service/NotificationInboxSseServiceTest.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Analyze (java-kotlin)
- GitHub Check: coverage
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java
⚙️ CodeRabbit configuration file
src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.
- 코멘트는 반드시 한국어로 작성한다.
- 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
- 각 코멘트 첫 줄에 심각도를
[LEVEL: high|medium|low]형식으로 반드시 표기한다.- 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
- 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
- 가능하면 재현 조건 및 실패 시나리오도 포함한다.
- 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
- 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
- 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
- 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
- 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.
Files:
src/main/java/gg/agit/konect/domain/notification/service/NotificationInboxSseService.java
**/*
⚙️ CodeRabbit configuration file
**/*: 공통 리뷰 톤 가이드:
- 모든 코멘트는 첫 줄에
[LEVEL: ...]태그를 포함한다.- 과장된 표현 없이 사실 기반으로 작성한다.
- 한 코멘트에는 하나의 이슈만 다룬다.
- 코드 예시가 필요하면 최소 수정 예시를 제시한다.
- 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.
Files:
src/main/java/gg/agit/konect/domain/notification/service/NotificationInboxSseService.javasrc/test/java/gg/agit/konect/unit/domain/notification/service/NotificationInboxSseServiceTest.java
- send 실패 후 completeWithError 호출도 이미 종료된 emitter와 경합할 수 있어 정리 단계의 예외가 다시 상위로 전파되지 않도록 별도 보호 구문을 추가 - 알림 전송 실패 처리의 목적은 끊어진 emitter를 제거하는 것이므로 종료 경쟁에서 생기는 IllegalStateException은 로그만 남기고 삼키도록 선택 - 기존 단위 테스트를 다시 실행해 알림 inbox SSE 경로가 회귀 없이 유지되는지 확인
- subscribe 경로의 completion callback 타이밍에 따라 테스트가 false positive가 될 수 있어 완료된 emitter를 직접 주입하는 방식으로 재현 조건을 고정 - 이번 테스트의 목적은 IllegalStateException 정리 분기를 안정적으로 검증하는 것이므로 구독 로직 부수효과보다 완료된 emitter 상태 자체를 최소 셋업으로 구성 - 수정 후 NotificationInboxSseService 단위 테스트를 다시 실행해 회귀 없이 통과함을 확인
* fix: 완료된 SSE emitter 전송 예외를 정리하도록 처리 - 이미 complete된 emitter에 send를 시도하면 IllegalStateException이 발생할 수 있어 알림 전송 자체보다 끊어진 연결 정리를 우선하도록 변경 - IOException만 completeWithError로 마무리하고 IllegalStateException은 emitter 제거로만 끝내 이미 종료된 emitter를 다시 종료하면서 예외가 전파되는 상황을 막음 - 완료된 emitter가 맵에 남아 있어도 예외 없이 정리되는 단위 테스트를 추가해 재연 경로를 고정하고 회귀를 방지 * fix: SSE emitter 종료 경합 예외를 추가로 흡수 - send 실패 후 completeWithError 호출도 이미 종료된 emitter와 경합할 수 있어 정리 단계의 예외가 다시 상위로 전파되지 않도록 별도 보호 구문을 추가 - 알림 전송 실패 처리의 목적은 끊어진 emitter를 제거하는 것이므로 종료 경쟁에서 생기는 IllegalStateException은 로그만 남기고 삼키도록 선택 - 기존 단위 테스트를 다시 실행해 알림 inbox SSE 경로가 회귀 없이 유지되는지 확인 * test: 완료된 SSE emitter 테스트를 결정적으로 고정 - subscribe 경로의 completion callback 타이밍에 따라 테스트가 false positive가 될 수 있어 완료된 emitter를 직접 주입하는 방식으로 재현 조건을 고정 - 이번 테스트의 목적은 IllegalStateException 정리 분기를 안정적으로 검증하는 것이므로 구독 로직 부수효과보다 완료된 emitter 상태 자체를 최소 셋업으로 구성 - 수정 후 NotificationInboxSseService 단위 테스트를 다시 실행해 회귀 없이 통과함을 확인
🔍 개요
🚀 주요 변경 내용
NotificationInboxSseService에서IOException뿐 아니라 완료된 emitter 전송 시 발생하는IllegalStateException도 함께 처리하도록 변경했습니다.IOException정리 과정에서 호출하는completeWithError도 별도try-catch로 감싸, emitter가 이미 종료된 경쟁 상황에서도 추가 예외가 전파되지 않도록 했습니다.subscribe()의 completion callback 부수효과에 기대지 않고, 완료된SseEmitter를 직접 주입해 예외 정리 경로를 결정적으로 재현하도록 바꿨습니다.💬 참고 사항
./gradlew test --tests \"gg.agit.konect.unit.domain.notification.service.NotificationInboxSseServiceTest\"✅ Checklist (완료 조건)