limited-planet-15554
12/23/2025, 6:21 AMtall-airline-16756
12/23/2025, 6:21 AMtall-airline-16756
12/23/2025, 6:22 AMsession.on('close') 이벤트가 발생하지 않는” 문제에 대해 답변드릴게요 — 왜 그럴 수 있는지와 빠르게 확인할 수 있는 항목들을 안내합니다.
먼저 가능한 원인 (주요 포인트)
• 네트워크 단절이나 클라이언트의 비정상 종료로 인해 정상적인 종료 시퀀스가 실행되지 않으면 `close`가 발생하지 않습니다.
• 에이전트의 종료 훅(예: session.shutdown() 또는 유사 호출)이 호출되지 않거나 실패한 경우 close 이벤트가 방출되지 않습니다.
• 워커 프로세스가 충돌(crash)하거나 강제 종료되면 정리 루틴이 실행되지 않아 이벤트가 생략될 수 있습니다.
• 세션/룸에서 발생하는 disconnected 같은 다른 이벤트 처리 로직에 문제가 있으면 기대하던 close 흐름이 차단될 수 있습니다.
빠른 점검 항목 (순서대로 확인 권장)
1. 로그 확인: 에이전트 종료 시점 전후의 에러/예외 로그, SIP 종료 시그널(BYE 등) 수신 기록을 확인하세요.
2. 종료 호출 확인: 에이전트 코드에서 정상 종료 시 `session.shutdown()`(또는 사용 중인 API의 종료 메서드)을 명시적으로 호출하는지 확인하세요.
3. 프로세스 종료 방식: 워커가 SIGINT/SIGTERM 등 정상 시그널로 종료되는지, 아니면 OOM/Crash로 죽는지 확인하세요.
4. Shutdown 콜백 등록: ctx.add_shutdown_callback() 같은 종료 콜백으로 세션 정리 로직을 강제 실행하도록 구성했는지 확인하세요.
5. 대체 이벤트 감지: disconnected 등 다른 룸/세션 이벤트를 수신해 비정상 종료를 감지하고 별도 정리 로직을 실행하는지 확인하세요.
추가로 도와드리려면 아래 정보 중 일부를 알려주세요
• 에이전트 종료/세션 정리 관련 코드(종료 부분) 스니펫
• 워커가 종료될 때 보이는 로그(오류 포함)나 SIP 신호(예: BYE 수신 여부)
• 워커가 실행되는 환경(컨테이너인지, 프로세스 관리 도구 사용 여부)
• 문제가 발생한 재현 조건(항상 발생하는지, 간헐적인지)
원하시면 제공하신 코드/로그를 기반으로 더 구체적인 원인 진단과 수정 예시(종료 훅 추가/로그 포인트 등)를 바로 제안해드릴게요.
Sources: Connecting to LiveKit | LiveKit docs | Job lifecycle | LiveKit docs | Collect recording consent with tasks | LiveKit docs | Company directory phone assistant | LiveKit docslimited-planet-15554
12/23/2025, 6:25 AMtall-airline-16756
12/23/2025, 6:25 AMjob_ctx.shutdown() 직후 프로세스가 즉시 exit 되는지 로그로 확인하세요.
• `job_ctx.shutdown()`이 실제로 세션의 정리(예: session.shutdown() 호출)를 트리거하지 않거나 예외로 실패했을 수 있습니다.
◦ 확인: job_ctx.shutdown() 내부에서 세션 종료 호출이 발생하는지, 예외가 발생했는지 로그/스택트레이스로 확인하세요.
• session.on("close") 리스너가 등록되기 전에 세션이 닫혀 이벤트를 놓쳤을 수 있습니다.
◦ 확인: 리스너 등록 시점이 세션 생성 직후인지, 또는 비동기 흐름에서 늦게 등록되는지 코드 흐름을 검토하세요.
• 워커가 크래시(uncaught exception, OOM)로 종료되어 정상적인 종료 훅이 실행되지 않았을 수 있습니다.
◦ 확인: 프로세스 종료 코드, 핵심 덤프, 컨테이너 런타임 로그 확인.
해결 권장 조치 (우선순위 순)
1. shutdown 흐름을 동기적으로 보장
◦ job_ctx.shutdown() 이후 세션 정리 완료를 기다리는 코드를 추가하거나, shutdown 콜백에서 await session.shutdown() 같은 명시적 호출을 하세요.
◦ 종료 시 예외가 있으면 재시도/로그를 남기도록 하세요.
1. 종료 콜백 강제 등록
◦ `ctx.add_shutdown_callback()`로 강제 정리 로직(세션 종료 호출 및 이벤트 대기)을 등록해 정상 종료 경로가 항상 실행되게 하세요.
1. `session.on("close")`를 포괄적으로 감지하도록 보완
◦ `room.on("disconnected")`나 다른 세션/connection 상태 이벤트를 같이 수신해, `close`가 발생하지 않을 때 대체 정리 로직을 실행하도록 하세요.
1. 리스너 등록 시점 고정
◦ 세션 생성 직후 session.on("close") 리스너를 등록해 이벤트 누락을 방지하세요.
1. 로그와 모니터링 강화
◦ shutdown 진입/종료, session.shutdown() 호출, close 이벤트 수신을 남기는 상세 로그를 추가하세요. 문제 재현 시 로그로 흐름을 추적하면 원인 파악이 빨라집니다.
추가로 필요합니다 — 몇 가지 확인 질문
• job_ctx.shutdown() 호출 직후 워커 프로세스가 바로 종료되나요, 아니면 정상적으로 몇 초 대기하나요?
• job_ctx.shutdown() 내부에 session.shutdown() 또는 동등한 세션 정리 호출이 있나요? 가능하면 해당 종료 부분 코드(몇 줄)를 공유해 주세요.
• 워커가 컨테이너 안에서 돌아가나요(예: Kubernetes), 또는 단일 프로세스로 실행하나요?
• 로그에서 session.shutdown() 호출 시점과 `session.on("close")`를 기다리는 로그가 어떻게 찍히는지 샘플 로그가 있으면 도움이 됩니다.
원하시면 코드 스니펫(종료 로직)과 관련 로그를 붙여 주시면, 그걸 기반으로 구체적으로 어떤 위치에 `await`나 shutdown 콜백을 넣을지, 예시 코드 수정까지 제안해드릴게요.limited-planet-15554
12/23/2025, 6:57 AMtall-airline-16756
12/23/2025, 6:58 AMsession.say() 호출로 RuntimeError: AgentSession isn't running)에 맞춰 바로 적용 가능한 해결책과 안전한 체크 패턴을 정리해드릴게요. 또한, 추가로 확인해주시면 좋은 정보도 요청합니다.
요점(무엇에 답하는지): 세션이 running 상태인지 확인하는 방법과, session.say() 호출 시점에서 발생하는 예외를 방지하는 안전한 패턴입니다.
해결책 요약
• 세션 상태 확인(호출 전)
◦ 안전한 간단 체크:
if getattr(session, "_state", None) != "closed":
speech_handle = session.say("...")
else:
logger.warning("Cannot speak: session is not running")
• 또는 현재 재생 중인지 확인:
if session.current_speech and not session.current_speech.done():
# 현재 재생 중
• shutdown/종료 시퀀스 보장
a. participant_disconnected 핸들러에서 job_ctx.shutdown() 호출 후 즉시 session.say() 같은 동작을 하면 안 됩니다. 항상 현재 재생이 끝나는 것을 기다리세요:
if session.current_speech:
await session.current_speech.wait_for_playout()
session.shutdown(reason="Session ended")
1. job_ctx.shutdown() 내부가 세션 정리를 트리거하지 않는다면, 명시적으로 await session.shutdown() 또는 session.shutdown() 호출을 하세요.
2. 종료 콜백 등록:
◦ `ctx.add_shutdown_callback()`로 세션 정리(및 await 필요 작업)를 보장하세요.
• 이벤트 누락 방지
◦ session.on("close") 리스너는 세션 생성 직후 등록하세요. 리스너 등록이 늦으면 이벤트를 놓칠 수 있습니다.
◦ participant_disconnected / SIP 상태 변경 핸들러에서 바로 종료 플래그를 세우고(예: session._shutdown_scheduled = True) 실제 종료는 현재 재생이 끝난 뒤 수행하는 패턴을 권장합니다.
• 로그/예외 처리 강화
◦ session.say() 호출 부근에 예외 처리 추가:
try:
speech_handle = session.say("...")
except RuntimeError:
logger.warning("Tried to say after session ended")
• job_ctx.shutdown() 진입/완료, session.shutdown() 호출, session.on("close") 수신 시점에 상세 로그를 추가하세요.
추가로 알려주시면 더 구체적으로 도와드릴 수 있습니다
• participant_disconnected 핸들러의 관련 코드(특히 job_ctx.shutdown() 직전/직후 부분)
• job_ctx.shutdown() 내부에서 세션 종료를 어떻게 처리하는지(코드나 설명)
• 워커 환경(컨테이너/K8s 또는 로컬 프로세스) 및 프로세스 종료 로그(있다면)
• session.on("close") 리스너 등록 위치의 코드 스니펫
원하시면 제공해주신 코드에 맞춰 안전한 await 위치, shutdown 콜백 예시, 그리고 session.say() 호출 전 체크용 헬퍼 함수를 바로 만들어 드릴게요.
Sources: Agent session | LiveKit docs