Skip to content

feat: deliver notification SSE across instances via Redis pub/sub - #60

Merged
idktomorrow merged 4 commits into
developfrom
feature/notification-sse-redis
Aug 6, 2026
Merged

idktomorrow merged 4 commits into
developfrom
feature/notification-sse-redis

Conversation

@idktomorrow

@idktomorrow idktomorrow commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

작업 내용

  • 알림 SSE 전송을 서버 메모리 기반에서 Redis Pub/Sub 기반으로 전환
  • 서버가 여러 대로 늘어나도, 유저가 실제로 연결된 인스턴스와 무관하게 알림이 정상 전달되도록 개선

변경 사항

  • NotificationSseServiceImpl.publish(): 로컬 emitter 직접 전송 대신 Redis 채널 발행으로 변경
  • NotificationSseMessage: Redis 채널에 실어보낼 메시지(userId + 알림 내용)
  • NotificationRedisSubscriber: Redis 채널 구독, 이 인스턴스에 연결된 유저면 실제 SSE 전송 (없으면 무시)
  • NotificationRedisPubSubConfig: 채널/리스너/스레드풀 설정

체크리스트

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

참고 사항

로컬에서 테스트 완료
스크린샷 2026-08-06 014046
스크린샷 2026-08-06 014103

관련 이슈

Summary by CodeRabbit

  • 새 기능

    • 여러 서버 인스턴스 간 알림을 중계하는 Redis 기반 SSE 알림 기능을 추가했습니다.
    • 사용자의 실시간 연결로 알림을 안정적으로 전달합니다.
  • 개선

    • 알림 발행과 수신을 비동기로 처리해 실시간 전달 성능과 안정성을 높였습니다.
    • 메시지 처리 및 전송 실패를 기록하고 문제가 발생한 연결을 정리합니다.
    • 알림 발행 실패 시 관련 오류 정보를 제공합니다.

@idktomorrow
idktomorrow requested review from SungHuii and jaejo August 5, 2026 17:03
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@idktomorrow, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d9ce196f-ecb9-46fd-8949-63590bb18ab0

📥 Commits

Reviewing files that changed from the base of the PR and between 1cc927c and 1f07fc3.

📒 Files selected for processing (1)
  • momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java
📝 Walkthrough

Walkthrough

Redis Pub/Sub으로 인스턴스 간 알림을 중계한다. NotificationSseServiceImpl은 알림을 Redis에 발행한다. NotificationRedisSubscriber는 메시지를 검증하고 로컬 SSE emitter로 전달한다.

Changes

Redis SSE 알림 중계

Layer / File(s) Summary
알림 메시지 계약과 Redis 발행
momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationSseMessage.java, momogo-api/src/main/java/com/momogo/api/notification/service/NotificationSseServiceImpl.java, momogo-core/src/main/java/com/momogo/core/common/exception/GlobalErrorCode.java
NotificationSseMessage가 사용자 ID와 알림 응답을 표현한다. NotificationSseServiceImpl은 메시지를 JSON으로 직렬화해 Redis 채널에 발행한다. 직렬화 실패에는 SSE_PUBLISH_FAILED를 사용한다.
Redis Pub/Sub 실행 구성
momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisExecutorConfig.java, momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java
알림 토픽과 메시지 리스너를 구성한다. 메시지 처리 실행기와 구독 실행기를 RedisMessageListenerContainer에 연결한다.
로컬 SSE 전송
momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisSubscriber.java
Redis 메시지의 필수 필드를 검증한다. 유효한 사용자 emitter에 notifications 이벤트를 전송한다. 전송에 실패한 emitter는 오류 상태로 종료한다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NotificationSseServiceImpl
  participant Redis
  participant RedisMessageListenerContainer
  participant NotificationRedisSubscriber
  participant LocalSseEmitter

  NotificationSseServiceImpl->>Redis: NotificationSseMessage JSON 발행
  Redis->>RedisMessageListenerContainer: notification-sse-channel 메시지 전달
  RedisMessageListenerContainer->>NotificationRedisSubscriber: handleMessage 호출
  NotificationRedisSubscriber->>LocalSseEmitter: notifications 이벤트 전송
Loading

Possibly related PRs

Suggested reviewers: jaejo, sunghuii

🚥 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 제목은 Redis Pub/Sub를 사용한 인스턴스 간 알림 SSE 전달이라는 PR의 주요 변경 사항을 정확하고 간결하게 설명합니다.
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-redis

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

🧹 Nitpick comments (1)
momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java (1)

56-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

인스턴스 간 전달을 검증하는 통합 테스트를 추가하세요.

이 구성은 채널, listener container, executor를 함께 연결합니다. 로컬 수동 테스트만으로는 직렬화, 구독, 인스턴스별 emitter 선택의 회귀를 막기 어렵습니다.

Testcontainers Redis 기반 테스트를 추가하세요. 서로 다른 NotificationEmitterRegistry를 가진 두 subscriber를 구독시키고, 대상 사용자가 연결된 registry만 notifications 이벤트를 받는지 검증하세요. 연결이 없는 인스턴스의 무시 동작과 잘못된 JSON 처리도 포함하세요.

장점은 핵심 분산 전달 계약을 자동으로 검증하는 점입니다. 단점은 테스트 실행 시간이 늘어나는 점입니다.

As per path instructions, 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/redis/NotificationRedisPubSubConfig.java`
around lines 56 - 72, 이 구성의 분산 Redis Pub/Sub 계약을 검증하는 Testcontainers Redis 통합
테스트를 추가하세요. 서로 다른 NotificationEmitterRegistry를 사용하는 두 subscriber의
RedisMessageListenerContainer를 구성하고, 한 registry에 연결된 사용자만 notifications 이벤트를
수신하며 다른 인스턴스는 무시하는지 검증하세요. 구독 및 직렬화를 포함하고, 잘못된 JSON 메시지가 안전하게 처리되는 경우도 테스트하세요.

Source: Path instructions

🤖 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/redis/NotificationRedisSubscriber.java`:
- Around line 25-35: Validate the deserialized result immediately after
readValue in handleMessage, checking message, message.userId(),
message.notification(), and message.notification().id() for null or missing
values. When validation fails, log a warning and return before calling
emitterRegistry.findAllByUserId or using the notification ID, while preserving
normal processing for valid messages.

---

Nitpick comments:
In
`@momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java`:
- Around line 56-72: 이 구성의 분산 Redis Pub/Sub 계약을 검증하는 Testcontainers Redis 통합
테스트를 추가하세요. 서로 다른 NotificationEmitterRegistry를 사용하는 두 subscriber의
RedisMessageListenerContainer를 구성하고, 한 registry에 연결된 사용자만 notifications 이벤트를
수신하며 다른 인스턴스는 무시하는지 검증하세요. 구독 및 직렬화를 포함하고, 잘못된 JSON 메시지가 안전하게 처리되는 경우도 테스트하세요.
🪄 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: 783cdee2-fb92-423d-8bf2-8bace8c25af3

📥 Commits

Reviewing files that changed from the base of the PR and between 74f16e2 and 7532b61.

📒 Files selected for processing (4)
  • momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java
  • momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisSubscriber.java
  • momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationSseMessage.java
  • momogo-api/src/main/java/com/momogo/api/notification/service/NotificationSseServiceImpl.java

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

수고하셨습니다 ! 👍 코멘트 확인 부탁드립니다~

@jaejo jaejo 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.

고생하셨습니다!

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

🧹 Nitpick comments (1)
momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java (1)

32-35: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Pub/Sub serializer에 JavaTimeModule을 적용하세요.

NotificationResponse.createdAtOffsetDateTime이고, Jackson2JsonRedisSerializer<>(NotificationSseMessage.class)는 기본적으로 JavaTimeModule이 없습니다. 따라서 구독 측 역직렬화가 실패합니다. 발행 측과 동일한 Jackson 설정을 serializer에 직접 전달하는 컨테이너 Bean을 생성해 구독 메시지 계약의 시간 타입을 처리하세요. 컨테이너 errorHandler는 실패 결과를 로그/통계로 남기도록 보강하는 것도 적합합니다.

🤖 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/redis/NotificationRedisPubSubConfig.java`
around lines 32 - 35, Update notificationListenerAdapter to use a Jackson
ObjectMapper configured with JavaTimeModule when constructing the
NotificationSseMessage serializer, matching the publisher’s Jackson settings so
OffsetDateTime deserializes correctly. Register the configured serializer
through the appropriate Redis listener container Bean, and enhance its
errorHandler to record failed subscription processing in the existing logging or
metrics mechanism.

Source: Path instructions

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

Nitpick comments:
In
`@momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java`:
- Around line 32-35: Update notificationListenerAdapter to use a Jackson
ObjectMapper configured with JavaTimeModule when constructing the
NotificationSseMessage serializer, matching the publisher’s Jackson settings so
OffsetDateTime deserializes correctly. Register the configured serializer
through the appropriate Redis listener container Bean, and enhance its
errorHandler to record failed subscription processing in the existing logging or
metrics mechanism.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f5d712dd-2981-4cc2-b4e6-51c70fb8647b

📥 Commits

Reviewing files that changed from the base of the PR and between 7532b61 and 1cc927c.

📒 Files selected for processing (5)
  • momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisExecutorConfig.java
  • momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisPubSubConfig.java
  • momogo-api/src/main/java/com/momogo/api/notification/redis/NotificationRedisSubscriber.java
  • momogo-api/src/main/java/com/momogo/api/notification/service/NotificationSseServiceImpl.java
  • momogo-core/src/main/java/com/momogo/core/common/exception/GlobalErrorCode.java

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

수고하셨습니다 👍

@idktomorrow
idktomorrow merged commit 465e4b1 into develop Aug 6, 2026
2 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