Skip to content

feat: 대기 등록 중복 체크 Redis 전환으로 성능 개선 - #42

Merged
Jinyoung-Kim96 merged 4 commits into
devfrom
feat/41-redis-check
May 19, 2026
Merged

Jinyoung-Kim96 merged 4 commits into
devfrom
feat/41-redis-check

Conversation

@Jinyoung-Kim96

@Jinyoung-Kim96 Jinyoung-Kim96 commented May 19, 2026

Copy link
Copy Markdown
Contributor

📝 작업 내용

대기 등록 시 DB 조회가 병목현상이 일어나서 동시 80명 한계 발생,
대기열 서비스의 본연의 역할 ( 트래픽 폭발 시 예약 서비스 보호 )을 위해
중복 체크를 Redis로 전환하여 성능 개선 예상

🚀 주요 변경 사항

완료한 이슈 번호 #41
Close #41

✅ 자체 체크리스트 (필수)

  • ./gradlew build 실행 결과 정상 (인증샷 첨부)
  • IntelliJ HTTP Client 테스트 완료 (인증샷 첨부)
  • 팀 내 컨벤션 준수 및 불필요한 로그, import 제거
  • 중요한 변경 사항이 팀에 공유되었는지

📸 테스트 인증샷

image

💬 리뷰어 전달사항 (선택)

특별히 봐주었으면 하는 부분이나 논의가 필요한 점을 적어주세요.

  • 논의점


📎 참고 자료

관련 문서, 레퍼런스 링크 등이 있다면 여기에 첨부해주세요.

Summary by CodeRabbit

  • 개선 사항
    • 중복 대기 등록 차단 로직을 최적화하여 더욱 빠르고 안정적인 응답 제공
    • 대기열 라이프사이클 전반에서 사용자 상태 관리 강화

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@Jinyoung-Kim96 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 36 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca38a2da-2fda-4fa3-b4ff-9060ab1ec55a

📥 Commits

Reviewing files that changed from the base of the PR and between 1fd8dc7 and 0e82503.

📒 Files selected for processing (3)
  • src/main/java/com/michelet/waiting/application/port/WaitingActivationPort.java
  • src/main/java/com/michelet/waiting/application/service/WaitingService.java
  • src/main/java/com/michelet/waiting/infrastructure/redis/RedisWaitingActivationAdapter.java
📝 Walkthrough

개요

대기 등록 중복 체크를 DB 쿼리 기반에서 Redis 기반으로 전환합니다. 포트 계약을 정의하고 Redis 어댑터로 구현한 후 서비스 플로우에 통합하며, 기존 DB 메서드를 제거합니다.

변경 사항

Redis 기반 사용자 중복 체크

계층 / 파일 요약
포트 계약: 사용자 상태 관리 API
src/main/java/com/michelet/waiting/application/port/WaitingActivationPort.java
WaitingActivationPort 인터페이스에 existsUser(restaurantId, userId), addUser(restaurantId, userId), removeUser(restaurantId, userId) 메서드 3개가 추가됩니다.
Redis 어댑터: 사용자 상태 저장소 구현
src/main/java/com/michelet/waiting/infrastructure/redis/RedisWaitingActivationAdapter.java
USER_PREFIX 상수와 buildUserKey() 메서드를 추가하고, 포트의 3개 메서드를 구현하여 waiting:user:{restaurantId}:{userId} 키로 사용자 상태를 Redis에서 관리합니다.
서비스 통합: 사용자 상태 관리 실행
src/main/java/com/michelet/waiting/application/service/WaitingService.java
enterWaiting에서 중복 체크를 existsUser 호출로 변경하고 이후 addUser를 호출합니다. cancelWaiting, activateNextBatch, expireWaitings에서는 각 종료 시점에 removeUser를 호출합니다.
레거시 제거: DB 기반 중복 체크 메서드 삭제
src/main/java/com/michelet/waiting/domain/repository/WaitingRepository.java, src/main/java/com/michelet/waiting/infrastructure/persistence/jpa/WaitingRepositoryImpl.java
findWaitingByRestaurantId(restaurantId) 메서드가 인터페이스와 구현체에서 제거되고, 관련 import이 정리됩니다.

추정 코드 리뷰 노력

🎯 2 (Simple) | ⏱️ ~10-15분

관련 PR

제안 리뷰어

  • githyj-jang
  • Sehi55
  • ji-circle

🐰 Redis 키가 반짝반짝, ✨
중복 체크는 더 빠르게!
DB 쿼리는 안녕히,
포트-어댑터-서비스 삼각편대
대기열이 한숨을 쉰다 🎉

🚥 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 제목은 'Redis 전환으로 성능 개선'이라는 주요 변경사항을 명확하게 요약하고 있으며, 전체 changeset의 핵심 목표를 잘 반영합니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 issue #41의 요구사항을 완전히 충족합니다: WaitingActivationPort에 중복 체크 메서드 추가, RedisWaitingActivationAdapter에 Redis 기반 구현, WaitingService에서 DB 조회 제거 및 Redis 사용으로 전환되었습니다.
Out of Scope Changes check ✅ Passed WaitingRepository 메서드 제거 등 모든 변경사항이 Redis 기반 중복 체크 마이그레이션이라는 명확한 목표와 일관성 있게 관련되어 있으며, 범위를 벗어난 변경사항은 없습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/41-redis-check

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 and usage tips.

@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: 4

🤖 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/michelet/waiting/application/port/WaitingActivationPort.java`:
- Around line 26-33: The current two-step contract (existsUser + addUser) in
WaitingActivationPort creates a TOCTOU race; replace or augment it with a single
atomic reservation method (e.g., reserveUser(UUID restaurantId, UUID userId):
boolean) on WaitingActivationPort that attempts an atomic check-and-set and
returns true if the user was reserved and false if already present, and keep
removeUser for cleanup; implement the adapter using Redis SETNX or a Lua script
with TTL to guarantee atomicity so concurrent requests cannot both succeed.

In `@src/main/java/com/michelet/waiting/application/service/WaitingService.java`:
- Around line 61-65: After enqueuing the token with
waitingActivationPort.add(command.restaurantId(), saved.getToken().value()), a
subsequent failure in waitingActivationPort.addUser(command.restaurantId(),
command.userId()) leaves the Redis queue token orphaned; update WaitingService
to handle this by performing compensation: wrap the addUser call in a try/catch
and on any exception call the corresponding removal method on
waitingActivationPort (e.g.,
waitingActivationPort.remove(command.restaurantId(), saved.getToken().value())
or the appropriate “delete token” API) to delete the queued token, then rethrow
or propagate the original error; alternatively, swap the order (addUser before
add) if semantically safe, but prefer the try/catch compensation to avoid
orphaned tokens.
- Around line 177-178: ACTIVE 저장 후
waitingActivationPort.removeUser(restaurantId, waiting.getUserId())에서 예외가 발생하면
잘못된 Redis 토큰 복구가 실행되는 문제입니다; WaitingService의 ACTIVE 저장/후속 작업 흐름을 변경해 ACTIVE 저장이
성공했는지 여부를 명시적으로 추적하고(예: boolean activatedSaved 변수) outer catch 블록에서 Redis 토큰 복구로
복원하는 분기를 activatedSaved == false일 때만 실행하도록 하거나, removeUser 호출을 별도의 try-catch로
감싸서 예외를 로깅만 하고 재던지지 않도록 처리해 removeUser 예외가 Redis 복구 로직을 트리거하지 않게 하세요 (참고 심볼:
waitingActivationPort.removeUser(...)와 현재의 catch 블록 내 Redis 토큰 복구 코드).

In
`@src/main/java/com/michelet/waiting/infrastructure/redis/RedisWaitingActivationAdapter.java`:
- Around line 41-43: The buildUserKey method lacks null checks for restaurantId
and userId unlike buildKey/buildSeqKey; update buildUserKey to validate both
inputs (e.g., throw IllegalArgumentException or NullPointerException consistent
with buildKey/buildSeqKey) and return the key only after validation so you never
produce a "null" segment that could pollute user flags—refer to buildKey and
buildSeqKey for the exact validation behavior and mirror that here.
🪄 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: ee566d0b-d3a4-4d40-9a0d-aa0c8f30fbcd

📥 Commits

Reviewing files that changed from the base of the PR and between 7567338 and 1fd8dc7.

📒 Files selected for processing (5)
  • src/main/java/com/michelet/waiting/application/port/WaitingActivationPort.java
  • src/main/java/com/michelet/waiting/application/service/WaitingService.java
  • src/main/java/com/michelet/waiting/domain/repository/WaitingRepository.java
  • src/main/java/com/michelet/waiting/infrastructure/persistence/jpa/WaitingRepositoryImpl.java
  • src/main/java/com/michelet/waiting/infrastructure/redis/RedisWaitingActivationAdapter.java
💤 Files with no reviewable changes (1)
  • src/main/java/com/michelet/waiting/domain/repository/WaitingRepository.java

Comment thread src/main/java/com/michelet/waiting/application/port/WaitingActivationPort.java Outdated
Comment thread src/main/java/com/michelet/waiting/application/service/WaitingService.java Outdated

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

확인했습니다!

@Jinyoung-Kim96
Jinyoung-Kim96 merged commit 17d0b13 into dev May 19, 2026
4 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.

[FEAT] 대기 등록 중복 체크 Redis 전환으로 성능 개선

2 participants