Skip to content

✨Feat: 매칭 상태 자동 전환 Scheduler 구현#66

Merged
angoroa merged 1 commit intodevelopfrom
feat/match-scheduler
Mar 9, 2026
Merged

✨Feat: 매칭 상태 자동 전환 Scheduler 구현#66
angoroa merged 1 commit intodevelopfrom
feat/match-scheduler

Conversation

@angoroa
Copy link
Member

@angoroa angoroa commented Mar 8, 2026

#️⃣ Issue Number

📝 요약(Summary)

  • MatchStatus 1분마다 체크해서 바꿔주는 스케줄러 구현
  • scheduledAt 도달 시 OPEN/FULL → CLOSED
  • scheduledAt + durationMinutes 도달 시 CLOSED → COMPLETED

🛠️ PR 유형

어떤 변경 사항이 있나요?

  • 새로운 기능 추가
  • 버그 수정
  • CSS 등 사용자 UI 디자인 변경
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 테스트 추가, 테스트 리팩토링
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📸스크린샷 (선택)

💬 공유사항 to 리뷰어

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • 커밋 메시지 컨벤션에 맞게 작성했습니다.
  • 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).

Summary by CodeRabbit

릴리즈 노트

  • 새로운 기능
    • 경기 상태 자동 업데이트 기능 추가. 진행 중인 경기는 자동으로 종료되고, 완료된 경기는 자동으로 완료 상태로 변경됩니다.

@angoroa angoroa linked an issue Mar 8, 2026 that may be closed by this pull request
2 tasks
@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 2026

🐰 변경사항 분석

Walkthrough

Spring Scheduling을 활성화하고, 매치룸 상태를 자동으로 업데이트하는 스케줄러를 구현했습니다. 저장소에 두 개의 상태 전환 쿼리를 추가하고, 매분 실행되는 스케줄 컴포넌트를 생성하여 OPEN/FULL → CLOSED와 CLOSED → COMPLETED 전환을 자동화합니다.

Changes

Cohort / File(s) Summary
Spring Scheduling 활성화
src/main/java/com/be/sportizebe/SportizeBeApplication.java
@EnableScheduling 어노테이션과 해당 import 추가하여 Spring 스케줄링 기능 활성화
매치 상태 전환 쿼리
src/main/java/com/be/sportizebe/domain/match/repository/MatchRoomRepository.java
@Modifying 어노테이션이 적용된 두 개의 native SQL 메서드 추가: closeStartedMatches()는 예약시간 도달한 OPEN/FULL 상태를 CLOSED로, completeFinishedMatches()는 예약시간 + 지속시간이 경과한 CLOSED 상태를 COMPLETED로 변경
자동 상태 업데이트 스케줄러
src/main/java/com/be/sportizebe/domain/match/scheduler/MatchStatusScheduler.java
매분 실행되는 스케줄 컴포넌트로, MatchRoomRepository의 두 메서드를 호출하여 매치 상태를 자동으로 전환하고 변경 건수를 로깅

Sequence Diagram(s)

sequenceDiagram
    participant Scheduler as Spring Scheduler
    participant Task as MatchStatusScheduler
    participant Repo as MatchRoomRepository
    participant DB as Database

    Scheduler->>Task: updateMatchStatuses() (매분 실행)
    Task->>Repo: closeStartedMatches()
    Repo->>DB: UPDATE match_rooms SET status=CLOSED<br/>(WHERE status IN (OPEN, FULL)<br/>AND scheduled_at <= NOW())
    DB-->>Repo: 업데이트된 행 개수 반환
    Repo-->>Task: closedCount 반환

    Task->>Repo: completeFinishedMatches()
    Repo->>DB: UPDATE match_rooms SET status=COMPLETED<br/>(WHERE status=CLOSED<br/>AND scheduled_at + duration <= NOW())
    DB-->>Repo: 업데이트된 행 개수 반환
    Repo-->>Task: completedCount 반환

    Task->>Task: 변경사항 로깅 (건수 > 0인 경우)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 시간이 흐르고 경기가 시작되면,
스케줄러가 깨어나 상태를 전환하고,
OPEN에서 CLOSED로, CLOSED에서 COMPLETED로,
자동으로 흐르는 매칭의 운명,
매분마다 똑똑, 시계는 정확하게! ⏰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main change: implementing a scheduler for automatic match status transitions, which matches the core functionality added across three files.
Linked Issues check ✅ Passed The PR fully implements both linked issue #65 objectives: OPEN/FULL → CLOSED transition and CLOSED → COMPLETED transition based on scheduledAt timestamps.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the match status scheduler: repository methods, scheduler component, and Spring scheduling enablement. No extraneous modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/match-scheduler

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.

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.

🧹 Nitpick comments (4)
src/main/java/com/be/sportizebe/domain/match/repository/MatchRoomRepository.java (2)

50-57: @Modifying에 clearAutomatically 옵션 고려 필요

벌크 UPDATE 쿼리 실행 후 영속성 컨텍스트에 이미 로드된 MatchRoom 엔티티들은 자동으로 갱신되지 않습니다. 동일 트랜잭션 내에서 변경된 엔티티를 다시 조회할 경우 stale 데이터가 반환될 수 있습니다.

현재 스케줄러에서는 별도 조회 로직이 없어 당장 문제는 없지만, 향후 확장성을 위해 clearAutomatically = true 옵션 추가를 권장합니다.

♻️ 권장 수정안
-    `@Modifying`
+    `@Modifying`(clearAutomatically = true)
     `@Query`(value = """
         UPDATE match_rooms
         SET status = 'CLOSED'
         WHERE status IN ('OPEN', 'FULL')
           AND scheduled_at <= NOW()
         """, nativeQuery = true)
     int closeStartedMatches();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/be/sportizebe/domain/match/repository/MatchRoomRepository.java`
around lines 50 - 57, The `@Modifying` bulk update in MatchRoomRepository (method
closeStartedMatches()) can leave stale entities in the persistence context;
update the `@Modifying` annotation to include clearAutomatically = true so the
EntityManager clears managed MatchRoom entities after the UPDATE. Locate the
`@Modifying` on closeStartedMatches() and add clearAutomatically = true to ensure
subsequent reads in the same transaction return fresh data.

60-67: 데이터 증가 시 성능을 위한 인덱스 고려

두 쿼리 모두 statusscheduled_at 컬럼을 조건으로 사용합니다. 매치 데이터가 증가하면 전체 테이블 스캔으로 인해 성능 저하가 발생할 수 있습니다.

복합 인덱스 추가를 권장합니다:

CREATE INDEX idx_match_rooms_status_scheduled_at 
ON match_rooms(status, scheduled_at);

또한 이 메서드에도 동일하게 @Modifying(clearAutomatically = true) 적용을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/be/sportizebe/domain/match/repository/MatchRoomRepository.java`
around lines 60 - 67, Add a composite index on (status, scheduled_at) to prevent
full table scans as match_rows grow (e.g., CREATE INDEX
idx_match_rooms_status_scheduled_at ON match_rooms(status, scheduled_at);) and
update the repository method annotation for int completeFinishedMatches() in
MatchRoomRepository to use `@Modifying`(clearAutomatically = true) so the
persistence context is cleared after the bulk update.
src/main/java/com/be/sportizebe/domain/match/scheduler/MatchStatusScheduler.java (2)

22-31: 예외 처리 추가 권장

스케줄러에서 예외 발생 시 해당 실행은 실패하지만 다음 주기에는 다시 실행됩니다. 그러나 디버깅과 모니터링을 위해 예외 로깅을 추가하는 것이 좋습니다.

♻️ 예외 처리 추가 제안
     `@Scheduled`(fixedRate = 60_000)
     `@Transactional`
     public void updateMatchStatuses() {
+        try {
             int closed = matchRoomRepository.closeStartedMatches();
             int completed = matchRoomRepository.completeFinishedMatches();

             if (closed > 0 || completed > 0) {
                 log.info("[MatchScheduler] CLOSED: {}건, COMPLETED: {}건", closed, completed);
             }
+        } catch (Exception e) {
+            log.error("[MatchScheduler] 상태 업데이트 중 오류 발생", e);
+        }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/be/sportizebe/domain/match/scheduler/MatchStatusScheduler.java`
around lines 22 - 31, The updateMatchStatuses method in MatchStatusScheduler
should catch and log any unexpected exceptions from
matchRoomRepository.closeStartedMatches() and
matchRoomRepository.completeFinishedMatches() to aid debugging and monitoring;
wrap the body of updateMatchStatuses in a try-catch, keep the `@Transactional`
behavior, and on exception call log.error with a clear message (e.g.,
"[MatchScheduler] failed to update match statuses") plus the
exception/stacktrace and any contextual info (closed/completed when available)
so failures are recorded without preventing future scheduled runs.

24-26: 서비스 레이어와의 동시성 고려

스케줄러의 벌크 UPDATE가 서비스 레이어(MatchServiceImpl의 join, leave, cancel 등)와 동시에 실행될 경우, 사용자 액션으로 인한 상태 변경과 충돌할 수 있습니다.

현재 쿼리는 status 컬럼을 WHERE 조건으로 사용하므로 대부분의 경우 안전하지만, 엣지 케이스에서 예상치 못한 동작이 발생할 수 있습니다. 향후 문제 발생 시 낙관적 락(@Version) 또는 쿼리에 updated_at 조건 추가를 고려해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/be/sportizebe/domain/match/scheduler/MatchStatusScheduler.java`
around lines 24 - 26, The bulk updater updateMatchStatuses calls
matchRoomRepository.closeStartedMatches() and completeFinishedMatches() which
can race with service-layer methods (MatchServiceImpl.join/leave/cancel); to
fix, add concurrency protection either by enabling optimistic locking on the
MatchRoom entity (add a `@Version` field and ensure repository update queries
respect version) or modify the repository update SQL to include an updated_at
(or last_modified) condition so you only update rows that haven't changed since
a read—pick one approach and implement it for both closeStartedMatches and
completeFinishedMatches so scheduler updates won't overwrite concurrent user
actions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@src/main/java/com/be/sportizebe/domain/match/repository/MatchRoomRepository.java`:
- Around line 50-57: The `@Modifying` bulk update in MatchRoomRepository (method
closeStartedMatches()) can leave stale entities in the persistence context;
update the `@Modifying` annotation to include clearAutomatically = true so the
EntityManager clears managed MatchRoom entities after the UPDATE. Locate the
`@Modifying` on closeStartedMatches() and add clearAutomatically = true to ensure
subsequent reads in the same transaction return fresh data.
- Around line 60-67: Add a composite index on (status, scheduled_at) to prevent
full table scans as match_rows grow (e.g., CREATE INDEX
idx_match_rooms_status_scheduled_at ON match_rooms(status, scheduled_at);) and
update the repository method annotation for int completeFinishedMatches() in
MatchRoomRepository to use `@Modifying`(clearAutomatically = true) so the
persistence context is cleared after the bulk update.

In
`@src/main/java/com/be/sportizebe/domain/match/scheduler/MatchStatusScheduler.java`:
- Around line 22-31: The updateMatchStatuses method in MatchStatusScheduler
should catch and log any unexpected exceptions from
matchRoomRepository.closeStartedMatches() and
matchRoomRepository.completeFinishedMatches() to aid debugging and monitoring;
wrap the body of updateMatchStatuses in a try-catch, keep the `@Transactional`
behavior, and on exception call log.error with a clear message (e.g.,
"[MatchScheduler] failed to update match statuses") plus the
exception/stacktrace and any contextual info (closed/completed when available)
so failures are recorded without preventing future scheduled runs.
- Around line 24-26: The bulk updater updateMatchStatuses calls
matchRoomRepository.closeStartedMatches() and completeFinishedMatches() which
can race with service-layer methods (MatchServiceImpl.join/leave/cancel); to
fix, add concurrency protection either by enabling optimistic locking on the
MatchRoom entity (add a `@Version` field and ensure repository update queries
respect version) or modify the repository update SQL to include an updated_at
(or last_modified) condition so you only update rows that haven't changed since
a read—pick one approach and implement it for both closeStartedMatches and
completeFinishedMatches so scheduler updates won't overwrite concurrent user
actions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 8fce4c7a-aec5-4921-950f-d16bede337c7

📥 Commits

Reviewing files that changed from the base of the PR and between 9875e28 and 1661b7e.

📒 Files selected for processing (3)
  • src/main/java/com/be/sportizebe/SportizeBeApplication.java
  • src/main/java/com/be/sportizebe/domain/match/repository/MatchRoomRepository.java
  • src/main/java/com/be/sportizebe/domain/match/scheduler/MatchStatusScheduler.java

@angoroa angoroa merged commit a62cfb6 into develop Mar 9, 2026
1 check 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: 매칭상태 자동 전환 스케줄러 구현

1 participant