fix(backend): STT 콜백이 유실되면 면접이 영구히 멈추던 문제 - #188
Merged
Conversation
음성 답변은 `(transcribing)` placeholder 로 먼저 저장되고 `callback.voice` 가 도착해야 내용이 채워진다. 그 콜백이 오지 않으면(AI 크래시·DLQ 격리·브로커 단절) 메시지는 그 상태로 남는다. 프론트 턴 판정(`currentTurn`)에서 이 메시지는 FAILED 도 아니고 질문도 아니라 **답변 차례가 영영 오지 않는다** — 세션 시간 초과로 면접이 통째로 끝날 때까지 사용자는 "답변을 받아 적고 있어요…" 화면에 갇힌다. 질문 생성 쪽은 #144 로 실패 신호(callback status=FAILED)를 만들어 같은 문제를 없앴는데 음성 경로에는 대응이 없었다. - `StaleTranscriptionSweeper` — 기본 2분 주기로 `interview.voice.stale-transcription-minutes` (기본 5분)를 넘긴 placeholder 를 찾는다. 진행 중·미삭제 세션의 것만 본다 - `VoiceTranscriptionRecoveryService.failStaleTranscription` — FAILED 로 확정하고 세션·유저 채널에 SSE 통지(`STT_CALLBACK_TIMEOUT`). 메시지마다 독립 트랜잭션이라 하나가 실패해도 나머지는 정리된다 - 확정 직전 상태를 다시 확인한다 — 스위퍼가 목록을 만든 뒤 콜백이 도착했으면 건드리지 않는다(완료된 답변을 실패로 되돌리는 것이 더 나쁘다) FAILED 로 두면 기존 STT 실패 경로를 그대로 탄다: 프론트 `currentTurn` 의 INTERVIEWEE+FAILED 분기가 답변 차례로 돌리고, 백엔드 `resolveAnswerParent` 가 같은 질문에 대한 텍스트 재답변을 받는다. 새 UX 를 만들지 않고 이미 검증된 경로에 합류시켰다. 테스트 `VoiceTranscriptionRecoveryServiceTest` (3) — FAILED 확정 + 양 채널 통지, 그 사이 전사가 도착한 경우 건드리지 않음, 메시지 부재 시 무동작.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
음성 인식 점검에서 나온 가장 큰 건
음성 답변은
(transcribing)placeholder 로 먼저 저장되고callback.voice가 도착해야 내용이 채워진다. 그 콜백이 오지 않으면 복구 경로가 없다 — AI 크래시, DLQ 격리, 브로커 단절 중 무엇이든.프론트 턴 판정(
domain/session/lib/turn.ts)에서 이 메시지는:askable도 아니다→
WAITING_FOR_QUESTION으로 고정되어 답변 차례가 영영 오지 않는다. 사용자는 "답변을 받아 적고 있어요…" 화면에 갇히고, 세션 시간 초과로 면접이 통째로 끝날 때까지 아무것도 못 한다.질문 생성 쪽은 #144 로 실패 신호(
callback.questions status=FAILED)를 만들어 같은 문제를 없앴다. 음성 경로만 남아 있었다.수정
StaleTranscriptionSweeper— 기본 2분 주기로interview.voice.stale-transcription-minutes(기본 5분)를 넘긴 placeholder 를 찾는다. 진행 중(IN_PROGRESS)·미삭제 세션의 것만 본다VoiceTranscriptionRecoveryService.failStaleTranscription— FAILED 로 확정하고 세션·유저 채널 양쪽에 SSE 통지(STT_CALLBACK_TIMEOUT). 메시지마다 독립 트랜잭션이라 하나가 실패해도 나머지는 정리된다기존
SessionTimeoutSweeper/SessionTimeoutService와 같은 구조다(스위퍼는 조회만, 상태 변경은 메시지 단위 트랜잭션 서비스).새 UX 를 만들지 않았다
FAILED 로 두면 이미 검증된 경로에 합류한다:
currentTurn의INTERVIEWEE + FAILED분기가 답변 차례로 되돌린다InterviewMessageService.resolveAnswerParent가 같은 질문에 대한 텍스트 재답변을 받는다둘 다 STT 실패(
callback.voice의 errorCode 경로)를 위해 이미 존재하던 것이다. 유실도 실패의 한 형태로 합류시키는 게 맞다고 봤다.테스트
VoiceTranscriptionRecoveryServiceTest(3) — FAILED 확정 + 양 채널 통지, 그 사이 전사가 도착했으면 건드리지 않음, 메시지 부재 시 무동작.backend
test통과(ArchUnit 포함).영향 범위
interview.voice.stale-transcription-minutes(5),interview.voice.sweep-interval-ms(120000)@EnableScheduling은 이미 켜져 있다(SchedulingConfig)리뷰어 체크포인트
같은 점검의 다른 발견
WSAudioHandler, AI/internal/voice/stream(Deepgram Live), CorePOST .../voice/stream-begin이 모두 구현·문서화("활성")돼 있는데 프론트는 배치 업로드만 쓴다. 스트리밍을 쓰면 실시간 자막 + 대기 시간 대폭 감소. 기능 규모라 별도 판단 필요docs/ui-patterns.md §9에 규약만 있다