종료·정리¶
Socket Backend에는 서로 다른 세 수명주기가 있습니다.
- 응답 턴 종료: gate·USER lease·지연 표본을 반납
- 대화 최종화: 저장된 메시지의 분석·요약을 마무리
- WebSocket 세션 종료: 세션 맵과 외부 연결을 제거하고
ended_at기록
이 셋은 같은 시점에 일어나지 않을 수 있습니다. 특히 DIALOG_END와 DM의 session complete는
대화 최종화를 시작하지만 WebSocket 연결을 반드시 닫지는 않습니다.
턴 정리¶
sequenceDiagram
participant T as Turn Task
participant O as TTS/Client Output
participant L as Turn Latency
participant G as AudioInputGate
participant D as DM Processing Guard
participant A as Immediate Analysis
T->>O: TTS 오디오 전송
T->>O: dialog_response 전송
T->>L: 미완료 표본을 success/cancelled/failed로 확정
T->>G: resume(이 턴의 PauseToken)
T->>D: finishProcessing(이 턴의 Lease)
opt deferred-enabled=false
T->>A: USER WAV 분석 시작
end
gate는 유효한 END를 수락한 뒤 닫히고 TTS와 dialog_response 전송이 끝난 뒤 열립니다.
오류나 조기 반환도 finally를 통하므로 token과 lease를 반납합니다. 즉시 분석은 gate resume 뒤에
실행되어 다음 입력을 막지 않습니다.
TurnCompletedEvent는 EPD·오디오 자원 정리에 쓰입니다. TIMEOUT은 응답 수신 스레드에서 먼저 구 EPD
연결을 무효화하므로 늦게 실행된 이벤트가 새 연결을 닫지 않습니다. 그 밖의 turn-complete 이벤트는
EPD 연결과 연결 추적 상태를 정리합니다.
대화 최종화¶
최종화 트리거는 클라이언트 DIALOG_END, DM session_complete/context.session_ended,
실제 WebSocket 제거로 발행되는 SessionEndEvent입니다. 같은 dialog의 동시 호출은 single-flight로
합치며, 완료 후 새 CONFIRMED 메시지가 생기면 새 입력 버전으로 다시 실행할 수 있습니다.
sequenceDiagram
participant X as Finalization Trigger
participant F as DialogFinalizationService
participant R as Pending Record Tail
participant A as Analysis
participant C as Conversation Summary
participant B as Biomarker Summary
participant DB as PostgreSQL
participant M as Maumon
X->>F: finalizeDialogAsync(sessionId, dialogId)
F->>R: pending records 대기(최대 5초)
R-->>F: 완료 또는 timeout
opt 지연 분석 모드
F-->>X: analysis_processing(best effort)
end
par 분석 마무리
F->>A: deferred flush 또는 immediate future 대기
A->>DB: 발화별 분석 저장
A-->>F: 성공 여부
and 일반 대화 요약
F->>C: CONFIRMED 메시지 요약
C->>DB: 요약·키워드·감정 upsert
C-->>F: 성공 여부
end
F->>F: 두 작업 join
F->>B: 바이오마커 요약 생성
B->>DB: 대화 단위 바이오마커 요약 저장
B-->>F: 성공 여부
opt 일반 요약 성공
F-)M: 저장된 요약 write-back 예약
Note over F,M: 결과를 기다리지 않음
end
F-->>X: analysis_complete(best effort, 지연 모드)
일반 요약과 분석은 병렬이며, 바이오마커 요약은 둘의 join 뒤 실행합니다. 일반 요약은 “요약 행이 있는가”만 보지 않고 요약 시각 이후 새 메시지가 있는지 확인해 전체 대화를 다시 요약합니다. 마음온 회신은 이미 저장된 요약만 읽으며, 별도 가상 스레드에서 재시도 없이 실행합니다.
ended_at의 정확한 의미¶
ended_at은 보편적인 최종화 마지막 단계가 아닙니다
dialog.ended_at은 SessionEndEvent 리스너가 finalizeDialog를 호출하기 직전 최초 한 번
기록합니다. DIALOG_END나 DM 완료만으로 실행된 최종화는 ended_at을 기록하지 않습니다.
WebSocket이 실제로 세션 관리자에서 제거되기 전까지 NULL일 수 있습니다.
세션 종료 정리¶
정상 close, transport error, 유휴 세션 제거는 모두 세션 맵의 원자적 제거로 수렴합니다. 제거에
성공한 한 경로만 SessionEndEvent를 발행하고 활성 연결 게이지를 감소시킵니다. 이벤트 소비자는
다음을 멱등 정리합니다.
- 선택된 Conversation Engine과 OpenAI upstream
DmProcessingGuard, response/utterance generation,AudioInputGate- 무응답 타이머와 턴 지연 표본
- workspace별 연결 지표
- DM 원격 세션 회수
- EPD 연결·activity 상태
ended_at기록과 마지막 대화 최종화
OpenAI upstream이 비정상 종료되면 늦게 등록될 임시 artifact까지 record tail 뒤에서 폐기합니다. 로컬 세션 종료는 upstream close handshake를 요청하고 제한 시간 안에 끝나지 않으면 abort합니다.