3.9 KiB
3.9 KiB
rb8001 운영 트러블슈팅: LLM 이벤트 루프 오류 및 콜드메일 도메인 파싱 개선 (KST 2025-10-24)
상황 요약
- 8001(rb8001) 최근 로그에서 LLM 호출 실패 다수 확인: “Event loop is closed”, “coroutine … was never awaited”.
- Slack 콜드메일 피드백 흐름에서 리스트 생성 시 회사설명에 ‘CO’가 들어간 사례 발생(발신자: kmkim@koreage.co.kr, 제목: “해요코리아 IR 자료 송부의 건.”).
영향 범위
- LLM 경로: Slack 대화 처리 중 간헐적 실패 → 사용자에게 폴백 메시지 노출(“죄송합니다. 요청을 처리할 수 없습니다.”).
- 콜드메일: IR 지표가 N/A일 때 도메인 폴백이 ‘CO’로 잘못 표기되어 리스트 정보 품질 저하.
증거(근거 로그/지표)
- Docker(rb8001): ERROR “Gemini chat error: Event loop is closed”, RuntimeWarning “coroutine '..._invoke' was never awaited”.
- OpenSearch(dataprepper-static, UTC): 최근 6시간 내 rb8001에서 동일 에러 6건 확인.
- Health 체크: http://localhost:8001/health 200 OK, 관련 스킬(8505/8511/8515) healthy.
원인 분석
-
LLM 비동기 처리 버그(비동기/이벤트 루프 경계 문제)
- 비동기 API 호출 중 이벤트 루프 종료/부재 상황 발생 시 예외 처리 미흡 → 연쇄 실패.
- 일부 경로에서 await 누락으로 코루틴 미대기 경고 발생.
-
도메인 폴백 파싱 오류
- ‘koreage.co.kr’에서 2레벨 추출 로직(parts[-2])이 ‘CO’를 회사명으로 오인 추출.
조치 사항(코드 수정)
-
LLM 안정화 및 로깅 개선
- GeminiHandler: async 실패(“Event loop is closed”, “no running event loop”, “was never awaited” 포함) 시 동기
generate_content를run_in_executor로 폴백하여 안전 재시도.- 파일:
rb8001/app/llm/gemini_handler.py - 주요 변경: async → sync executor 폴백,
logger.exception로 스택트레이스 기록.
- 파일:
- Router/LLMService 로깅 강화:
logger.exception사용으로 예외 스택 기록.- 파일:
rb8001/app/router/router.py,rb8001/app/llm/llm_service.py
- 파일:
- GeminiHandler: async 실패(“Event loop is closed”, “no running event loop”, “was never awaited” 포함) 시 동기
-
콜드메일 회사명 파싱 정확도 개선
tldextract도입으로 eTLD+1 기준 파싱:koreage.co.kr→ domain=koreage확보.- 폴백 휴리스틱: 국가코드+세컨드레벨(co|com|or|ne|ac|go|gov|edu)+ccTLD 패턴 시
parts[-3]사용. - 파일:
rb8001/app/services/coldmail_processor.py - 의존성 추가:
tldextract>=5.1.2(파일:rb8001/requirements.txt)
배포 및 검증
- Gitea 푸시 후 서버(51124)에서
docker compose up -d --build로 재기동. - 헬스 확인:
curl http://localhost:8001/health200 OK, 관련 스킬 포트도 200 OK. - 회귀 확인:
- 최근 1분 로그 기준 “Event loop is closed/never awaited” 미발견.
- 컨테이너 내 파싱 테스트:
tldextract.extract('koreage.co.kr')→domain='koreage', suffix='co.kr'정상.
커밋 참조
- fix(llm): executor 폴백 + 예외 로깅 강화 —
eb27d1b→ 정리59baa69 - fix(coldmail): 도메인 파싱에 tldextract 적용 —
9629253
후속 조치(제안)
- Slack 경로 실제 사용자 시나리오 재현 테스트(의도 UNKNOWN 빈도/LLM 실패율 모니터링).
- OpenSearch 대시보드/쿼리 저장: “Event loop is closed”, “never awaited” 알람 룰 추가(UTC↔KST 변환 유의).
- 9024(robeing-monitor) 헬스 엔드포인트 정합성 확인(404 응답 시 문서화 또는 구현).
교훈(📌 Lessons Learned)
- 비동기 호출은 이벤트 루프 수명/스레드 경계, await 일관성 확보가 핵심이다(폴백 경로 필수).
- 로깅은 스택트레이스까지 남겨야 원인 추적이 가능하다.
- 이메일 도메인 파싱은 공공 접미사 목록(eTLD) 기반 라이브러리 사용으로 오인식 방지.
— 작성: happybell80, KST 2025-10-24