Skip to content

feat: send periodic heartbeat to keep notification SSE connections alive - #62

Merged
Junkov0 merged 2 commits into
developfrom
feature/notification-sse-heartbeat
Aug 7, 2026
Merged

Junkov0 merged 2 commits into
developfrom
feature/notification-sse-heartbeat

Conversation

@idktomorrow

@idktomorrow idktomorrow commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

작업 내용

  • SSE 연결이 오래 idle 상태일 때 중간 프록시/로드밸런서가 연결을 끊어버리는 문제 방지
  • 30초 주기로 연결된 모든 유저에게 하트비트 전송

변경 사항

  • MomogoApiApplication: @EnableScheduling 추가 (스케줄링 기능 활성화)
  • NotificationEmitterRegistry: findAll() 추가 (이 인스턴스의 모든 연결 조회)
  • NotificationSseHeartbeatScheduler: 30초마다 SSE comment(":heartbeat") 전송

체크리스트

  • 테스트 코드 작성 완료
  • 리뷰어 지정 완료

참고 사항

  • 로컬에서 60초 이상 대기하며 :heartbeat 라인이 30초 간격으로 반복 수신되는 것을 확인

관련 이슈

Summary by CodeRabbit

  • 새로운 기능
    • 실시간 알림 연결을 30초마다 자동으로 확인하고 유지하는 heartbeat 기능을 추가했습니다.
    • 연결 오류가 발생하면 해당 연결을 자동으로 종료하고 상태를 기록합니다.
    • 등록된 실시간 알림 연결을 안정적으로 관리하여 알림 수신이 중단될 가능성을 줄였습니다.

@idktomorrow
idktomorrow requested review from Junkov0 and SungHuii August 6, 2026 14:19
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 72ebed2f-969d-4c4a-b6ae-f97566a63f69

📥 Commits

Reviewing files that changed from the base of the PR and between 7ffbacc and 26d23c5.

📒 Files selected for processing (1)
  • momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java

📝 Walkthrough

Walkthrough

Spring 스케줄링을 활성화했습니다. 전체 SseEmitter 조회 기능을 추가했습니다. 스케줄러가 30초마다 모든 연결에 heartbeat를 전송하고 오류 연결을 종료합니다.

Changes

SSE heartbeat 전송

Layer / File(s) Summary
Spring 스케줄링 활성화
momogo-api/src/main/java/com/momogo/api/MomogoApiApplication.java
EnableScheduling@EnableScheduling을 추가했습니다.
SSE 연결 조회 및 heartbeat 전송
momogo-api/src/main/java/com/momogo/api/notification/registry/NotificationEmitterRegistry.java, momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java
findAll()이 모든 SseEmitter를 반환합니다. 스케줄러가 30초마다 heartbeat를 전송합니다. IOException 또는 IllegalStateException 발생 시 로그를 기록하고 해당 연결을 오류로 종료합니다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SpringScheduler
  participant NotificationSseHeartbeatScheduler
  participant NotificationEmitterRegistry
  participant SseEmitter
  SpringScheduler->>NotificationSseHeartbeatScheduler: 30초 주기 sendHeartbeat() 실행
  NotificationSseHeartbeatScheduler->>NotificationEmitterRegistry: findAll() 호출
  NotificationEmitterRegistry-->>NotificationSseHeartbeatScheduler: 전체 SseEmitter 목록 반환
  loop 각 SSE 연결
    NotificationSseHeartbeatScheduler->>SseEmitter: heartbeat comment 전송
    alt IOException 또는 IllegalStateException 발생
      NotificationSseHeartbeatScheduler->>SseEmitter: 오류와 함께 연결 종료
    end
  end
Loading

Possibly related PRs

Suggested reviewers: sunghuii, junkov0

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 30초 주기의 알림 SSE 하트비트 전송이라는 주요 변경 사항을 정확하고 간결하게 설명합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/notification-sse-heartbeat

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java (2)

24-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

[권장] heartbeat 성공·실패·주기 회귀 테스트를 추가하세요.

PR objective에서 테스트가 미완료로 표시되어 있습니다. 최소한 다음 사례를 검증하세요.

  • 여러 사용자와 여러 emitter가 모두 heartbeat comment를 받는지 확인합니다.
  • 한 emitter의 IOException 또는 IllegalStateException이 다음 emitter 전송을 중단하지 않는지 확인합니다.
  • lifecycle callback 이후 findAll()에서 emitter가 제외되는지 확인합니다.
  • 실제 60초 이상 대기하지 말고, 짧은 주기 또는 제어 가능한 scheduler를 사용합니다.

직접 호출하는 unit test는 빠르고 결정적입니다. Application context 기반 test는 @EnableScheduling과 component scanning을 검증하지만 실행 시간이 길고 더 취약합니다.

As per path instructions: **/main/**/*.java 파일은 Java 21 기준으로 리뷰하며, 객체지향·실무 활용성·불필요한 로직·클린코드·서비스/도메인 설계·공통 예외 처리를 확인합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java`
around lines 24 - 33, The NotificationSseHeartbeatScheduler tests are missing
coverage for heartbeat delivery and scheduling behavior. Add fast, deterministic
unit tests around sendHeartbeat() verifying all emitters receive the heartbeat
comment, IOException and IllegalStateException from one emitter do not prevent
subsequent sends, lifecycle callbacks remove emitters from
emitterRegistry.findAll(), and the interval is tested through a short or
controllable scheduler instead of waiting 60 seconds.

Source: Path instructions


20-24: 🩺 Stability & Availability | 🔵 Trivial

[운영 설정] SSE 하트비트 주기와 가장 짧은 idle timeout을 대조하세요.

SseEmitter는 30분으로 설정되어 있으므로 애플리케이션 내 timeout 문제는 없습니다. 하지만 배포 경로는 Nginx 재적재와 ALB_DNS_NAME을 사용하므로, Nginx, ALB 또는 JVM 프로세스 자체의 read_timeout/idle timeout이 30초 이하일 수 있습니다. SSE 연결이 하트비트보다 먼저 끊어지지 않도록 최소 1.5x 여유로 맞춰 배포 설정을 확인하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java`
around lines 20 - 24, Verify the deployment path settings used by
NotificationSseHeartbeatScheduler, including Nginx, ALB, and JVM process
read/idle timeouts, and configure the shortest timeout to be at least 1.5 times
HEARTBEAT_INTERVAL so SSE connections are not closed before a heartbeat.

Sources: Path instructions, MCP tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java`:
- Around line 26-32: Update the heartbeat loop in
NotificationSseHeartbeatScheduler to catch IllegalStateException alongside
IOException so a terminated emitter cannot stop broadcasting to remaining
emitters. Remove emitter.completeWithError(e) from the IOException handling and
retain warning logging while allowing the registry’s existing onError cleanup to
handle removal.
- Around line 24-28: Update sendHeartbeat() to submit each emitter’s send
operation to a bounded executor instead of performing sends serially in the
scheduled thread. Ensure each emitter has at most one in-flight heartbeat task,
while allowing different emitters to be processed independently and preserving
the existing heartbeat event and failure handling.

---

Nitpick comments:
In
`@momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java`:
- Around line 24-33: The NotificationSseHeartbeatScheduler tests are missing
coverage for heartbeat delivery and scheduling behavior. Add fast, deterministic
unit tests around sendHeartbeat() verifying all emitters receive the heartbeat
comment, IOException and IllegalStateException from one emitter do not prevent
subsequent sends, lifecycle callbacks remove emitters from
emitterRegistry.findAll(), and the interval is tested through a short or
controllable scheduler instead of waiting 60 seconds.
- Around line 20-24: Verify the deployment path settings used by
NotificationSseHeartbeatScheduler, including Nginx, ALB, and JVM process
read/idle timeouts, and configure the shortest timeout to be at least 1.5 times
HEARTBEAT_INTERVAL so SSE connections are not closed before a heartbeat.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: 59785e50-ded6-44b3-a421-6bef04b1a5ea

📥 Commits

Reviewing files that changed from the base of the PR and between 465e4b1 and 7ffbacc.

📒 Files selected for processing (3)
  • momogo-api/src/main/java/com/momogo/api/MomogoApiApplication.java
  • momogo-api/src/main/java/com/momogo/api/notification/registry/NotificationEmitterRegistry.java
  • momogo-api/src/main/java/com/momogo/api/notification/scheduler/NotificationSseHeartbeatScheduler.java

@MoMoGo-QuizPlatform MoMoGo-QuizPlatform deleted a comment from coderabbitai Bot Aug 6, 2026

@SungHuii SungHuii left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

수고하셨습니다 👍

@Junkov0 Junkov0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

따로 수정사항이 없는 것 같습니다.
작성 하느라 수고많으셨습니다!

@Junkov0
Junkov0 merged commit 160abd0 into develop Aug 7, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants