Skip to content

Conversation

@unifolio0
Copy link
Contributor

@unifolio0 unifolio0 commented Aug 8, 2025

🚩 Jira Ticket

SCRUM-77

🗣️ 리뷰 요구사항 (선택)

동시성 테스트를 했더니 DeadLock 현상이 발생해 우선 DeadLock을 없애는 방향으로 리팩토링 했습니다.

Summary by CodeRabbit

  • 버그 수정

    • 동시 예약 처리 시 예약 가능 인원 감소 및 증가 로직이 개선되어, 여러 사용자가 동시에 예약을 시도해도 정확하게 처리됩니다.
    • 예약 가능 인원이 부족할 때 안내 메시지가 더욱 명확하게 변경되었습니다.
  • 테스트

    • 동시 예약 상황에서의 정상 동작을 검증하는 테스트가 추가되었습니다.
    • 동시 실행을 지원하는 테스트 유틸리티가 도입되었습니다.
  • 기타

    • 예약 가능 인원 조정 관련 내부 로직이 안정적으로 개선되었습니다.

@unifolio0 unifolio0 self-assigned this Aug 8, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 8, 2025

Walkthrough

예약 서비스의 동시성 및 용량 감소 로직이 리팩토링되었습니다. 용량 감소 책임이 엔티티에서 도메인 서비스로 이동되었고, 관련 메서드와 예외 처리 방식이 변경되었습니다. 동시성 테스트를 위한 베이스 테스트 클래스와 예약 서비스 테스트가 추가되었습니다.

Changes

Cohort / File(s) Change Summary
예약 서비스 리팩토링
api-user/src/main/java/com/wellmeet/reservation/ReservationService.java
예약 시 용량 감소 로직이 엔티티 직접 호출에서 RestaurantDomainService의 메서드 호출로 변경됨.
테스트 베이스 및 동시성 테스트 추가
api-user/src/test/java/com/wellmeet/BaseServiceTest.java,
api-user/src/test/java/com/wellmeet/reservation/ReservationServiceTest.java
동시성 테스트 지원을 위한 추상 테스트 베이스 클래스 추가 및 예약 서비스의 동시성 테스트 케이스 신설.
도메인 서비스 계층 로직 분리
domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java,
domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/AvailableDateDomainService.java
예약 가능 날짜의 용량 감소 책임을 도메인 서비스 계층으로 이동. 용량 부족 시 예외 처리 및 용량 0일 때 예약 불가 처리 추가.
엔티티 책임 축소 및 검증 메서드 도입
domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDate.java
용량 감소 및 예외 처리 메서드 제거, 예약 가능 여부 검증 메서드(canNotReserve) 추가.
저장소 계층 용량/상태 변경 쿼리 추가
domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/repository/AvailableDateRepository.java
용량 감소 및 예약 불가 상태 변경을 위한 JPQL update 쿼리 메서드 2종 추가.
에러 메시지 변경
domain/src/main/java/com/wellmeet/domain/restaurant/exception/RestaurantErrorCode.java
용량 부족 시 에러 메시지 문구를 더 명확하게 변경.
테스트 설정 변경
api-user/src/test/resources/application.yml
테스트용 데이터베이스 설정에서 SQL 로그 비활성화 및 ddl-autocreate-drop에서 create로 변경.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ReservationService
    participant RestaurantDomainService
    participant AvailableDateDomainService
    participant AvailableDateRepository

    User->>ReservationService: reserve(예약 요청)
    ReservationService->>RestaurantDomainService: decreaseAvailableDateCapacity(availableDate, partySize)
    RestaurantDomainService->>AvailableDate: canNotReserve(partySize)
    alt 예약 불가
        RestaurantDomainService-->>ReservationService: throw RestaurantException
    else 예약 가능
        RestaurantDomainService->>AvailableDateDomainService: decreaseCapacity(availableDate, partySize)
        AvailableDateDomainService->>AvailableDateRepository: decreaseCapacity(id, partySize)
        AvailableDateDomainService->>AvailableDateRepository: changeIsNotAvailable(id) (if capacity == 0)
        RestaurantDomainService-->>ReservationService: 완료
    end
    ReservationService-->>User: 예약 결과 반환
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Possibly related PRs

Suggested labels

refactor, test

Suggested reviewers

  • ezcolin2

Poem

🐇
새로운 로직, 동시성의 춤,
토끼는 깡충, 테스트를 품.
엔티티 책임은 가벼워지고,
서비스 계층이 든든해졌네.
예약의 질서, 예외의 말,
깔끔한 코드에 토끼도 활짝!
🥕

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDate.java (1)

52-54: 메서드 네이밍 및 의도 표현을 명확히 해주세요.

canNotReserve는 Java 컨벤션에도 어색하고 부정형 네이밍이라 가독성이 떨어집니다.
cannotReserve, isNotReservable, 또는 긍정형인 isReservable로 바꾸는 편이 좋습니다.

-public boolean canNotReserve(int partySize) {
-    return !isAvailable || maxCapacity < partySize;
+public boolean isReservable(int partySize) {
+    return isAvailable && maxCapacity >= partySize;
}

호출부에서는 조건을 반대로 사용하면 됩니다. 긍정형은 읽기·유지보수 모두 수월합니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6410c88 and dc9c8b1.

📒 Files selected for processing (8)
  • api-user/src/main/java/com/wellmeet/reservation/ReservationService.java (2 hunks)
  • api-user/src/test/java/com/wellmeet/BaseServiceTest.java (1 hunks)
  • api-user/src/test/java/com/wellmeet/reservation/ReservationServiceTest.java (1 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java (1 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/AvailableDateDomainService.java (1 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDate.java (1 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/repository/AvailableDateRepository.java (2 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/exception/RestaurantErrorCode.java (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-10T02:52:48.337Z
Learnt from: unifolio0
PR: Team-soft-macaron/WellMeet-Backend#14
File: src/main/java/com/wellmeet/recommend/dto/RecommendRestaurantResponse.java:3-3
Timestamp: 2025-07-10T02:52:48.337Z
Learning: The Restaurant class is located at `com.wellmeet.restaurant.domain.Restaurant` after the package refactoring in the WellMeet-Backend project, not in a nested model package structure.

Applied to files:

  • api-user/src/main/java/com/wellmeet/reservation/ReservationService.java
  • domain/src/main/java/com/wellmeet/domain/restaurant/exception/RestaurantErrorCode.java
  • domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDate.java
📚 Learning: 2025-06-25T08:56:15.148Z
Learnt from: ezcolin2
PR: Team-soft-macaron/WellMeet-Backend#4
File: src/main/java/com/wellmeet/restaurant/domain/crawlingreview/domain/Atmosphere.java:15-16
Timestamp: 2025-06-25T08:56:15.148Z
Learning: CrawlingReview와 Restaurant 엔티티는 외부에서 수집한 식별자를 직접 사용하므로 GeneratedValue 없이 수동으로 ID를 설정하는 것이 적합하다.

Applied to files:

  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDate.java
🧬 Code Graph Analysis (3)
domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java (1)
domain/src/test/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDateTest.java (6)
  • Test (55-68)
  • AvailableDateTest (14-70)
  • assertThat (32-32)
  • assertThat (50-50)
  • Nested (16-69)
  • availableDate (65-65)
domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/repository/AvailableDateRepository.java (2)
domain/src/test/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDateTest.java (5)
  • Nested (16-69)
  • AvailableDateTest (14-70)
  • Test (37-53)
  • Test (55-68)
  • assertThat (32-32)
common-test/src/main/java/com/wellmeet/fixture/AvailableDateGenerator.java (1)
  • Component (9-23)
domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDate.java (1)
domain/src/test/java/com/wellmeet/domain/restaurant/availabledate/entity/AvailableDateTest.java (7)
  • Test (55-68)
  • Nested (16-69)
  • availableDate (65-65)
  • AvailableDateTest (14-70)
  • assertThat (32-32)
  • assertThat (50-50)
  • Test (37-53)
🔇 Additional comments (2)
api-user/src/main/java/com/wellmeet/reservation/ReservationService.java (1)

32-34: 엔티티 상태와 DB 상태 불일치 가능성

decreaseAvailableDateCapacity는 JPQL update로만 용량을 줄입니다. 이때 availableDate 엔티티의 maxCapacity, isAvailable 값은 메모리상 그대로라서 이후 로직(혹은 동일 트랜잭션 내 다른 서비스)에서 잘못된 정보를 사용할 수 있습니다.
EntityManager.refresh(availableDate) 호출이나 재조회로 엔티티 상태를 동기화하거나, 용량 변경을 아예 도메인 서비스/엔티티 레벨에서 수행해 JPA 더티체킹이 적용되도록 하는 편이 안전합니다.

domain/src/main/java/com/wellmeet/domain/restaurant/exception/RestaurantErrorCode.java (1)

18-18: 문구 변경에 따른 테스트 확인 필요

에러 메시지가 변경되었으므로, 단위테스트나 프런트엔드에서 문자열을 하드코딩해 비교하는 경우 모두 업데이트해야 합니다.

Comment on lines +55 to +64
executorService.submit(() -> {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
latch.countDown();
}
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

스레드 내부 예외가 테스트에 전파되지 않습니다

task.run() 안에서 발생한 예외를 스레드 내부에서 RuntimeException으로 다시 던지지만, Future를 수집하지 않아 메인 테스트 스레드가 이를 감지하지 못합니다.
실제 예외가 발생해도 테스트가 성공으로 끝날 수 있으므로, 예외를 ConcurrentLinkedQueue 등에 저장한 뒤 latch.await() 후 메인 스레드에서 한 번에 throw 하거나, ExecutorService.invokeAllFuture를 회수해 확인하는 방식을 권장합니다.

🤖 Prompt for AI Agents
In api-user/src/test/java/com/wellmeet/BaseServiceTest.java around lines 55 to
64, exceptions thrown inside the thread are caught and rethrown as
RuntimeException but not propagated to the main test thread because the Future
returned by executorService.submit is not collected. To fix this, collect the
Future objects returned by submit, then after latch.await(), iterate over these
Futures and call get() to rethrow any exceptions in the main thread, or
alternatively store exceptions in a thread-safe collection inside the catch
block and after latch.await(), check and throw them in the main thread to ensure
test failures are detected properly.

Comment on lines +74 to +84
for (Runnable task : tasks) {
executorService.submit(() -> {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
latch.countDown();
}
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

동일 문제: 예외 누락

위와 같은 이유로 리스트 기반 메서드도 예외가 숨겨집니다. 두 메서드를 공통 유틸로 추출하면서 예외 수집·재throw 로직을 함께 적용해 주세요.

🤖 Prompt for AI Agents
In api-user/src/test/java/com/wellmeet/BaseServiceTest.java around lines 74 to
84, the current code submits tasks to an executor but exceptions thrown inside
tasks are caught and rethrown inside the thread, causing them to be lost
outside. Refactor by extracting the task submission and exception handling into
a common utility method that collects exceptions from all tasks and rethrows
them after all tasks complete, ensuring no exceptions are silently swallowed.

Comment on lines +41 to +48
runAtSameTime(500, () -> reservationService.reserve(member.getId(), request));
List<Reservation> reservations = reservationRepository.findAll();
AvailableDate foundAvailableDate = availableDateRepository.findById(availableDate.getId()).get();

assertAll(
() -> assertThat(reservations).hasSize(1),
() -> assertThat(foundAvailableDate.getMaxCapacity()).isEqualTo(capacity - partySize)
);
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🛠️ Refactor suggestion

🧩 Analysis chain

스레드 실행 중 발생한 예외가 숨겨질 수 있습니다.

runAtSameTime(500, …) 내부에서 발생한 예외가 잡히지 않으면 테스트가 정상 통과하더라도 실제로는 일부 예약 로직이 실패했을 가능성이 있습니다.
CompletableFuture.allOf() 사용 등으로 각 태스크의 예외를 수집한 뒤 assertAll로 검증하도록 runAtSameTime 유틸을 개선하는 것을 권장합니다.


🏁 Script executed:

#!/bin/bash
rg -n "runAtSameTime"

Length of output: 598


🏁 Script executed:

#!/bin/bash
rg -n -A5 -B5 "protected void runAtSameTime" api-user/src/test/java/com/wellmeet/BaseServiceTest.java

Length of output: 1054


runAtSameTime 예외 처리 개선 필요

BaseServiceTest#runAtSameTime(int, Runnable) 메서드(파일: api-user/src/test/java/com/wellmeet/BaseServiceTest.java, 51–61라인)에서 task.run() 중 발생한 예외를 빈 catch 블록으로 처리해 버려, 스레드 실행 중 오류가 발생하더라도 테스트는 정상 통과하여 실제 로직 실패가 감춰질 수 있음이 확인되었습니다.

해결 방안 예시:

  • CompletableFuture를 이용해 CompletableFuture.allOf(...).join() 호출 시점에 모든 예외를 수집·재던지
  • ExecutorService.invokeAll(List<Callable<?>>) 후 반환된 Future.get() 호출로 예외를 명시적으로 확인

위와 같이 runAtSameTime 유틸을 개선하여 각 태스크 예외를 누락 없이 검증하도록 변경을 권장합니다.

· 대상 위치
– api-user/src/test/java/com/wellmeet/BaseServiceTest.java 51–61라인

🤖 Prompt for AI Agents
In api-user/src/test/java/com/wellmeet/BaseServiceTest.java around lines 51 to
61, the runAtSameTime method currently catches and ignores exceptions thrown by
tasks, causing test failures to be hidden. To fix this, refactor runAtSameTime
to use CompletableFuture.allOf(...).join() or ExecutorService.invokeAll with
Future.get() to collect and rethrow all exceptions from the concurrent tasks,
ensuring that any errors during task execution cause the test to fail as
expected.

Comment on lines 26 to 31
public void decreaseCapacity(AvailableDate availableDate, int partySize) {
availableDateRepository.decreaseCapacity(availableDate.getId(), partySize);
if (availableDate.getMaxCapacity() - partySize == 0) {
availableDateRepository.changeIsNotAvailable(availableDate.getId());
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

0 석 여부 판단 로직이 불안정합니다

availableDate.getMaxCapacity() - partySize업데이트 전 값을 기준으로 계산합니다. 동시 트래픽으로 이미 용량이 줄어들었을 수 있으므로, 0 석 판정이 빗나가 isAvailable 플래그가 갱신되지 않을 위험이 있습니다.
― JPQL update에서 capacity = capacity - :partySizecapacity = 0 조건으로 한 번에 is_available=false 를 세팅하거나, update 수행 뒤 SELECT capacity 로 최신 값을 확인해 결정을 내려주세요.

🤖 Prompt for AI Agents
In
domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/AvailableDateDomainService.java
around lines 26 to 31, the logic to determine zero capacity uses the pre-update
maxCapacity value, which can be outdated due to concurrent updates. To fix this,
modify the repository update method to perform a single JPQL update that
decreases capacity and sets isAvailable to false when capacity reaches zero, or
after decreasing capacity, query the latest capacity value before deciding to
update the isAvailable flag. This ensures the availability flag reflects the
current state accurately under concurrent conditions.

Comment on lines +57 to +62
public void decreaseAvailableDateCapacity(AvailableDate availableDate, int partySize) {
if (availableDate.canNotReserve(partySize)) {
throw new RestaurantException(RestaurantErrorCode.NOT_ENOUGH_CAPACITY);
}
availableDateDomainService.decreaseCapacity(availableDate, partySize);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

경합 조건으로 초과 예약 가능

canNotReserve() 검사는 메모리 상 값만 확인하므로 동시에 두 요청이 들어오면 둘 다 통과할 수 있습니다.
DB 레벨에서 UPDATE … SET capacity = capacity - :partySize WHERE id = :id AND capacity >= :partySize처럼 조건부 감소 후, 영향을 받은 행 수가 0이면 NOT_ENOUGH_CAPACITY 예외를 던지는 방식으로 원자성을 확보해 주세요.

🤖 Prompt for AI Agents
In
domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java
around lines 57 to 62, the current capacity check using canNotReserve() is not
atomic and can lead to race conditions allowing overbooking. Refactor the
decreaseAvailableDateCapacity method to perform a conditional update directly in
the database that decrements capacity only if sufficient capacity exists, such
as using an UPDATE statement with a WHERE clause checking capacity >= partySize.
After the update, check the number of affected rows; if zero, throw the
NOT_ENOUGH_CAPACITY exception to ensure atomicity and prevent concurrent
overbooking.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java (1)

57-62: 원자성 없는 사전 체크(TOCTOU)로 동시성 취약 — 단일 조건부 UPDATE로 일원화 필요

availableDate.canNotReserve(partySize)는 메모리 값 기반의 선행 검사라 동일 시점의 2요청이 모두 통과할 수 있습니다. 데드락/경합 최소화를 위해 사전 조회를 제거하고, DB 레벨의 “조건부 감소(UPDATE ... WHERE capacity >= :partySize)” 한 번으로 원자적으로 처리해 주세요. 감소 실패는 영향을 받은 행 수 0으로 판단해 NOT_ENOUGH_CAPACITY로 매핑하는 것이 안전합니다.

적용 제안:

-    if (availableDate.canNotReserve(partySize)) {
-        throw new RestaurantException(RestaurantErrorCode.NOT_ENOUGH_CAPACITY);
-    }
-    availableDateDomainService.decreaseCapacity(availableDate, partySize);
+    // 단일 DB 조건부 UPDATE에 위임하여 원자성/동시성 보장
+    availableDateDomainService.decreaseCapacity(availableDate, partySize);

확인 포인트:

  • AvailableDateDomainService.decreaseCapacity(...)가 내부적으로
    • 단일 SQL: UPDATE ... SET capacity = capacity - :partySize WHERE id = :id AND capacity >= :partySize
    • 결과 행 수가 0이면 RestaurantException(NOT_ENOUGH_CAPACITY)을 던지도록 구현되어 있는지.
  • 위 방식은 불필요한 선행 SELECT를 제거해 락 획득 순서를 단순화하고 데드락 가능성을 낮춥니다.
  • 가능하면 엔티티 대신 식별자(id) 기반으로 위임하는 것도 고려해 주세요(오래된 스냅샷 사용 리스크 감소).

검증 스크립트:

#!/bin/bash
# decreaseCapacity 구현과 조건부 UPDATE 존재 여부를 확인

echo "== Service: AvailableDateDomainService.decreaseCapacity =="
rg -n -A 10 -B 2 $'class AvailableDateDomainService' && rg -n -A 20 -B 2 $'decreaseCapacity\\s*\\('

echo "== Repository: AvailableDateRepository의 @Modifying 쿼리 =="
rg -n -A 5 -B 2 $'AvailableDateRepository'
rg -n -A 3 -B 3 $'UPDATE.+capacity\\s*=\\s*capacity\\s*-|capacity\\s*>=\\s*:\\s*partySize|decreaseCapacity'
🧹 Nitpick comments (2)
api-user/src/test/resources/application.yml (2)

17-17: SQL 로그 비활성화 자체는 OK. 환경변수로 토글 가능하도록 해두면 테스트 디버깅이 수월합니다.

주석 대신 기본 비활성화 + 환경변수로 on/off 가능하게 두는 방식을 제안합니다.

다음과 같이 변경하면 필요 시 SHOW_SQL 환경변수만 켜서 로그를 볼 수 있습니다.

-    #    show-sql: true
+    show-sql: ${SHOW_SQL:false}

20-20: format_sql 비활성화도 합리적입니다. 동일하게 토글 가능하도록 하면 유연성이 좋아집니다.

동시성 테스트 중에는 포맷팅 오버헤드 제거가 유리하지만, 이슈 분석 시 쉽게 켤 수 있어야 합니다.

-        #        format_sql: true
+        format_sql: ${JPA_FORMAT_SQL:false}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc9c8b1 and 7caff1c.

📒 Files selected for processing (5)
  • api-user/src/main/java/com/wellmeet/reservation/ReservationService.java (2 hunks)
  • api-user/src/test/resources/application.yml (1 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java (1 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/AvailableDateDomainService.java (1 hunks)
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/repository/AvailableDateRepository.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • api-user/src/main/java/com/wellmeet/reservation/ReservationService.java
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/repository/AvailableDateRepository.java
  • domain/src/main/java/com/wellmeet/domain/restaurant/availabledate/AvailableDateDomainService.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-10T02:52:48.337Z
Learnt from: unifolio0
PR: Team-soft-macaron/WellMeet-Backend#14
File: src/main/java/com/wellmeet/recommend/dto/RecommendRestaurantResponse.java:3-3
Timestamp: 2025-07-10T02:52:48.337Z
Learning: The Restaurant class is located at `com.wellmeet.restaurant.domain.Restaurant` after the package refactoring in the WellMeet-Backend project, not in a nested model package structure.

Applied to files:

  • domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java
⏰ 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). (1)
  • GitHub Check: build-and-push
🔇 Additional comments (1)
domain/src/main/java/com/wellmeet/domain/restaurant/RestaurantDomainService.java (1)

64-66: increaseCapacity 로직이 단일 UPDATE로 원자화 및 isAvailable 동기화 처리됨 확인됨

  • AvailableDateRepository.increaseCapacity 쿼리
    @Query("update AvailableDate a set a.maxCapacity = a.maxCapacity + :partySize, a.isAvailable = true where a.id = :id")
    단일 SQL로 capacity 증가와 가용 상태 동기화를 동시에 수행해 로스트 업데이트 방지 및 isAvailable=true 적용이 확인됩니다.

추가 변경 없이 현 구현 유지하셔도 됩니다.

dialect: org.hibernate.dialect.MySQLDialect
hibernate:
ddl-auto: create-drop
ddl-auto: create
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

ddl-auto를 create로 변경: 병렬 테스트/복수 컨텍스트 공유 시 스키마 경합 가능성 점검 필요

create는 컨텍스트 시작 시 기존 스키마를 드롭 후 재생성(종료 시 드롭 없음)합니다. 테스트가 병렬 실행되거나, 서로 다른 컨텍스트가 동일 DB를 공유하면 간헐적인 DROP/CREATE 경합, 락 대기, 실패가 발생할 수 있습니다. Testcontainers로 격리된 DB 사용 또는 테스트별 고유 스키마/DB명을 권장합니다. 최소한 환경변수로 제어 가능하게 두는 것이 안전합니다.

권장 변경(선택):

-      ddl-auto: create
+      ddl-auto: ${JPA_DDL_AUTO:create}

검증 스크립트(레포지토리 루트에서 실행):


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) ddl-auto 설정이 중복/충돌되는 곳이 없는지 확인"
rg -n "spring\.jpa\.hibernate\.ddl-auto|ddl-auto" -A 2 || true

echo
echo "2) JUnit 병렬 실행 설정 확인 (junit-platform.properties 등)"
fd -a junit-platform.properties || true
rg -n "junit\.jupiter\.execution\.parallel\.enabled" -A 2 || true

echo
echo "3) 컨텍스트 재시작을 유발할 수 있는 @DirtiesContext 사용 여부 확인"
rg -n "@DirtiesContext" -A 2 || true

echo
echo "4) 테스트 DB 격리를 위한 Testcontainers 사용 여부 확인"
rg -n "Testcontainers|MySQLContainer|DynamicPropertySource" -A 2 || true

Length of output: 1762


ddl-auto 설정 환경 변수화 적용 및 모듈별 중복 변경 필요
테스트 실행 시 create/create-drop 모드가 병렬 실행 또는 여러 컨텍스트가 동일 DB를 공유할 때 스키마 DROP/CREATE 충돌을 유발할 수 있습니다. 현재 다음 모듈의 테스트용 application.yml에 고정값으로 설정되어 있으므로 환경변수화해 기본값을 지정하도록 변경하세요.

수정 대상:

  • domain/src/test/resources/application.yml
  • api-owner/src/test/resources/application.yml
  • api-user/src/test/resources/application.yml

예시 (api-user 모듈):

--- a/api-user/src/test/resources/application.yml
+++ b/api-user/src/test/resources/application.yml
@@ -23,1 +23,1 @@
-      ddl-auto: create
+      ddl-auto: ${JPA_DDL_AUTO:create}

필요 시 JPA_DDL_AUTO 환경변수를 통해 각기 다른 모드(create, create-drop, none 등)를 유연히 제어할 수 있도록 설정해 두면 안전합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ddl-auto: create
ddl-auto: ${JPA_DDL_AUTO:create}
🤖 Prompt for AI Agents
In api-user/src/test/resources/application.yml at line 23, the ddl-auto property
is hardcoded to "create", which can cause schema conflicts during parallel test
executions or shared DB contexts. Modify this setting to use an environment
variable, such as JPA_DDL_AUTO, with a default value of "create" to allow
flexible control of the schema generation mode. Apply the same environment
variable approach to the ddl-auto settings in
domain/src/test/resources/application.yml and
api-owner/src/test/resources/application.yml to avoid duplication and ensure
consistent configuration across modules.

@unifolio0 unifolio0 merged commit 3086eab into Team-soft-macaron:develop Aug 8, 2025
1 of 2 checks passed
@unifolio0 unifolio0 deleted the SCRUM-77 branch August 8, 2025 08:12
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.

1 participant