Skip to content

fix(session): 세션 종료 동시성 하드닝 (#124 후속)#126

Merged
i3months merged 1 commit into
devfrom
feature/sweeper-concurrency-hardening
Jun 28, 2026
Merged

fix(session): 세션 종료 동시성 하드닝 (#124 후속)#126
i3months merged 1 commit into
devfrom
feature/sweeper-concurrency-hardening

Conversation

@i3months

Copy link
Copy Markdown
Member

변경 사항

회의적 멀티에이전트 리뷰(3인 반증단 3/3 검증)에서 발견한 #124 세션 스위퍼 동시성 결함 3건 수정. 모든 발견은 실제 코드로 재확인함.

결함

  1. [HIGH] 종료 세션 사후 변조QuestionsCallbackService.apply()가 status를 확인하지 않아(advanceToNextGeneral엔 있는 가드가 누락), 스위퍼/수동 종료 뒤 처리 대기 중이던 POOL/FOLLOWUP 콜백이 종료된 세션에 질문·placeholder를 INSERT.
  2. [MEDIUM] generate.feedback 이중 발행 — 락 없는 COMPLETED 전이로 동시 종료(스위퍼 vs 수동/콜백, 멀티 인스턴스) 시 SessionEndedEvent가 두 번 발행. 멱등 가드(existsBySession_Id)가 비동기로 생성되는 피드백 행에 의존해 무력화 → 중복 LLM 비용.
  3. [MEDIUM] 막판 답변 경합 — maxDuration 직전 제출 답변의 AFTER_COMMIT 발화가 스위퍼 종료와 겹쳐 종료 세션에 꼬리질문 누적.

수정

  • InterviewSessionRepository.finishIfInProgress — 조건부 UPDATE(WHERE status=IN_PROGRESS)로 종료 전이를 원자화. DB 행 락으로 직렬화돼 영향 행 1인 트랜잭션만 종료 부수효과를 발행 → 동시 종료에도 SessionEndedEvent 단 한 번.
  • 모든 종료 경로(SessionTimeoutService / SessionService.end / QuestionsCallbackService.endSession)가 이 게이트 사용.
  • QuestionsCallbackService.apply() + SessionFollowupRequester.onAnswerSubmittedisTerminal() 가드 → 종료 후 콜백/발화 드롭.
  • SessionStatus.isTerminal() 헬퍼 추가.

테스트

  • lost-race(전이 패배) 시 미발행 검증 추가, 기존 종료 경로 테스트 보강.
  • ./gradlew test 전체 통과.

비고

🤖 Generated with Claude Code

회의적 멀티에이전트 리뷰(3/3 검증)에서 발견한 #124 스위퍼 동시성 결함 3건.

1) [HIGH] 종료 세션 사후 변조: QuestionsCallbackService.apply()가 status 미확인 →
   스위퍼/수동 종료 뒤 늦게 도착한 POOL/FOLLOWUP 콜백이 종료 세션에 질문·placeholder
   INSERT. apply()에 isTerminal() 가드 추가(멱등 마킹 후 드롭).
2) [MEDIUM] generate.feedback 이중 발행: 락 없는 COMPLETED 전이로 동시 종료 시
   SessionEndedEvent 가 두 번 발행(멱등 가드가 비동기 생성 피드백 행에 의존해 무력화).
3) [MEDIUM] 막판 답변 발화가 종료 세션에 꼬리질문 누적.

수정:
- InterviewSessionRepository.finishIfInProgress: 조건부 UPDATE(WHERE status=IN_PROGRESS)로
  종료 전이를 원자화. 영향 행 1인 트랜잭션만 종료 부수효과 발행 → DB 행 락 직렬화로
  동시 종료(스위퍼·수동·콜백) 시 정확히 한 번만 SessionEndedEvent 발행.
- SessionTimeoutService/SessionService.end/QuestionsCallbackService.endSession 모두
  finishIfInProgress 게이트 사용.
- SessionFollowupRequester.onAnswerSubmitted 에 isTerminal() 가드.
- SessionStatus.isTerminal() 헬퍼 추가.
- 테스트: 종료 경쟁 패배(lost-race) 미발행 검증 추가, 기존 종료 테스트 보강. 전체 통과.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stackup Ready Ready Preview, Comment Jun 28, 2026 11:30am

@i3months i3months merged commit f10909e into dev Jun 28, 2026
3 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.

1 participant