feat: 채팅 도배 방지 (Flood Protection)#110
Conversation
- checkRate() 레이스 컨디션 수정: per-user synchronized 블록 적용 - 비활성 유저 타임스탬프 메모리 누수 방지: @scheduled eviction 추가 - handleMessageRateLimited에 @AsyncPublisher 어노테이션 추가
|
Warning Review limit reached
More reviews will be available in 18 minutes and 45 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
📝 Walkthrough개요사용자별 메시지 전송 빈도를 1초 5회로 제한하는 in-memory sliding window 기반 rate limiting과 반복 위반 시 점진적으로 증가하는 서버 사이드 cooldown(5초→15초→30초) 시스템을 구현합니다. Rate limit 초과 시 CHAT_RATE_LIMIT_EXCEEDED 오류와 남은 cooldown 시간(retryAfterMs)을 사용자 오류 큐로 전달합니다. 변경 사항채팅 도배 방지 통합 구현
시퀀스 다이어그램sequenceDiagram
participant Client
participant Controller as MessageWebSocketController
participant Limiter as MessageRateLimiter
participant Broadcaster as RoomMessageBroadcaster
participant Queue as UserQueue
Client->>Controller: send(userId, message)
Controller->>Limiter: checkRate(userId)
Limiter-->>Controller: allow or throw CustomException
alt Rate Limit Exceeded
Controller->>Controller: publishCustomError
Controller->>Broadcaster: emit MessageRateLimitedEvent
Broadcaster->>Queue: convertAndSendToUser(/queue/errors)
else Within Limit
Controller->>Controller: process message send
end
예상 코드 리뷰 난이도🎯 3 (Moderate) | ⏱️ ~25 분 관련 이슈
관련 PR
시
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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 |
There was a problem hiding this comment.
Pull request overview
WebSocket 기반 채팅/장소 공유 메시지 전송에 대해 사용자별 전송 빈도 제한과 서버 사이드 cooldown(반복 위반 시 점진 증가)을 추가하고, 제한 초과 시 클라이언트로 retryAfterMs를 포함한 전용 에러 이벤트를 전달하도록 확장한 PR입니다.
Changes:
MessageRateLimiter(in-memory sliding window + cooldownUntil/violations) 도입 및MessageCommandService.send/sharePlace진입 시 rate limit 선행 체크 추가CustomException.retryAfterMs추가 후,MessageRateLimitedEvent→RoomMessageBroadcaster→/user/queue/errors경로로retryAfterMs전달- 관련 단위/컨트롤러/브로드캐스터 테스트 및 기능 명세 문서 업데이트
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/com/howaboutus/backend/messages/service/MessageRateLimiter.java | 사용자별 sliding window + cooldown/점진 증가 로직 구현 |
| src/main/java/com/howaboutus/backend/messages/service/MessageCommandService.java | send/sharePlace 시작 시 rate limit 체크 추가 |
| src/main/java/com/howaboutus/backend/common/error/CustomException.java | retryAfterMs 필드 및 생성자 추가 |
| src/main/java/com/howaboutus/backend/common/error/ErrorCode.java | CHAT_RATE_LIMIT_EXCEEDED(429) 추가 |
| src/main/java/com/howaboutus/backend/realtime/event/MessageRateLimitedEvent.java | rate limit 전용 이벤트(재시도 시간 포함) 추가 |
| src/main/java/com/howaboutus/backend/realtime/service/dto/UserErrorPayload.java | /user/queue/errors payload에 retryAfterMs 확장 |
| src/main/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcaster.java | rate limited 이벤트 수신/유저 큐 전송 핸들러 추가 |
| src/main/java/com/howaboutus/backend/messages/controller/MessageWebSocketController.java | rate limit 예외를 전용 이벤트로 분기 발행하도록 변경 |
| src/test/java/com/howaboutus/backend/messages/service/MessageRateLimiterTest.java | sliding window/cooldown/점진 증가 동작 테스트 추가 |
| src/test/java/com/howaboutus/backend/messages/service/MessageServiceTest.java | send/sharePlace 경로에서 rate limit 예외 전파 테스트 추가 |
| src/test/java/com/howaboutus/backend/common/error/CustomExceptionTest.java | retryAfterMs 기본값/지정값 테스트 추가 |
| src/test/java/com/howaboutus/backend/messages/controller/MessageWebSocketControllerTest.java | rate limit 발생 시 이벤트 발행 테스트 추가 |
| src/test/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcasterTest.java | rate limited 이벤트가 user queue errors로 전달되는지 테스트 추가 |
| docs/ai/features.md | Flood Protection 기능/정책(점진 cooldown 포함) 문서 반영 |
| docs/superpowers/specs/2026-05-25-chat-flood-protection-design.md | Flood Protection 설계 문서 추가 |
| docs/superpowers/specs/2026-05-27-flood-protection-cooldown-design.md | 서버 사이드 cooldown/점진 제한 설계 문서 추가 |
| docs/superpowers/plans/2026-05-25-chat-flood-protection.md | 구현 계획 문서 추가 |
| docs/superpowers/plans/2026-05-27-flood-protection-cooldown.md | cooldown/점진 제한 구현 계획 문서 추가 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@src/main/java/com/howaboutus/backend/common/error/CustomException.java`:
- Around line 10-18: The CustomException constructors should call the
RuntimeException superclass with the error message so stack traces show a useful
message: in class CustomException update both constructors (the one taking
ErrorCode errorCode and the one taking ErrorCode errorCode, long retryAfterMs)
to invoke super(errorCode.getMessage()) before assigning fields so the exception
message is populated for logging.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: ca84f9eb-3a76-411d-9389-ef38c2d06a00
📒 Files selected for processing (18)
docs/ai/features.mddocs/superpowers/plans/2026-05-25-chat-flood-protection.mddocs/superpowers/plans/2026-05-27-flood-protection-cooldown.mddocs/superpowers/specs/2026-05-25-chat-flood-protection-design.mddocs/superpowers/specs/2026-05-27-flood-protection-cooldown-design.mdsrc/main/java/com/howaboutus/backend/common/error/CustomException.javasrc/main/java/com/howaboutus/backend/common/error/ErrorCode.javasrc/main/java/com/howaboutus/backend/messages/controller/MessageWebSocketController.javasrc/main/java/com/howaboutus/backend/messages/service/MessageCommandService.javasrc/main/java/com/howaboutus/backend/messages/service/MessageRateLimiter.javasrc/main/java/com/howaboutus/backend/realtime/event/MessageRateLimitedEvent.javasrc/main/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcaster.javasrc/main/java/com/howaboutus/backend/realtime/service/dto/UserErrorPayload.javasrc/test/java/com/howaboutus/backend/common/error/CustomExceptionTest.javasrc/test/java/com/howaboutus/backend/messages/controller/MessageWebSocketControllerTest.javasrc/test/java/com/howaboutus/backend/messages/service/MessageRateLimiterTest.javasrc/test/java/com/howaboutus/backend/messages/service/MessageServiceTest.javasrc/test/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcasterTest.java
|



변경 내용
CHAT_RATE_LIMIT_EXCEEDED에러와 남은 cooldown 시간(retryAfterMs)을/user/queue/errors로 전달CustomException에retryAfterMs필드 추가MessageRateLimitedEvent이벤트 및UserErrorPayload확장변경 이유
테스트
./gradlew build/review-code-against-docs스킬로 검증MessageRateLimiterTest(sliding window, cooldown, 점진 증가),MessageWebSocketControllerTest(rate limit 에러 이벤트 발행),MessageServiceTest(send/sharePlace 호출 시 checkRate 선행),RoomMessageBroadcasterTest(rate limited 이벤트 브로드캐스트),CustomExceptionTest(retryAfterMs 필드)체크리스트
하네스 변경 체크리스트
Summary by CodeRabbit
Release Notes
New Features
Documentation