DOCS/troubleshooting/251016_grpc_uvloop_blocking_error.md
Claude-51124 3fb2deff22 docs: 콜드메일 플로우 분석 및 3가지 문제 문서화
- 251016_grpc_uvloop_blocking_error: gRPC + uvloop 리소스 경합 문제
- 251016_naverworks_briefing_system_uuid_error: 시스템 사용자 UUID 검증 오류
- 251014_claude_coldmail_filter_tokenization_issue: 파인티처 메일 누락 사례 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 13:32:38 +09:00

96 lines
2.5 KiB
Markdown

# gRPC + uvloop BlockingIOError 리소스 경합
**날짜**: 2025-10-16
**작성자**: Claude
**관련 파일**: `rb8001/main.py`, `rb8001/app/llm/emotion_classifier.py`
---
## 문제 상황
### 발생 시점
- NaverWorks Daily Briefing 실행 시 (매일 09:00)
- 감정 분석 LLM 호출 중 발생 (09:00:03.240)
### 에러 로그
```
{"time":"2025-10-16 09:00:03,240","level":"ERROR","module":"asyncio"}
Exception in callback functools.partial(<bound method PollerCompletionQueue._handle_events of <grpc._cython.cygrpc.PollerCompletionQueue object>>)
File "grpc/_cython/_cygrpc/aio/completion_queue.pyx.pxi", line 147, in grpc._cython.cygrpc.PollerCompletionQueue._handle_events
BlockingIOError: [Errno 11] Resource temporarily unavailable
```
### 영향
- 작업 실패 없음 (NaverWorks Briefing 정상 완료)
- 로그 노이즈 발생으로 실제 오류 추적 방해
---
## 원인 분석
### 기술적 원인
- **uvloop**: rb8001 main.py에서 사용 중인 고성능 event loop
- **gRPC**: emotion_classifier.py에서 Vertex AI (Gemini) 호출 시 사용
- **리소스 경합**: uvloop의 epoll과 gRPC의 polling 메커니즘 충돌
### 발생 조건
1. uvloop 활성화 상태에서 gRPC 비동기 호출
2. 동시 다발적 LLM 요청 (감정 분석 + 요약 생성)
3. gRPC PollerCompletionQueue의 이벤트 처리 중 일시적 리소스 부족
---
## 해결 방안
### 1. gRPC 이벤트 루프 로깅 억제 (권장)
**위치**: rb8001/main.py:1-10
**현재**:
```python
import uvloop
uvloop.install()
```
**변경**:
```python
import uvloop
import logging
uvloop.install()
logging.getLogger("grpc").setLevel(logging.CRITICAL)
```
### 2. asyncio 기본 루프 사용 (성능 하락)
**위치**: rb8001/main.py:1-10
**변경**: uvloop.install() 제거, asyncio 기본 루프 사용
### 3. gRPC 채널 재사용 설정
**위치**: rb8001/app/llm/emotion_classifier.py
**확인 필요**: gRPC 채널 풀링 설정 확인
---
## 구현 완료
미구현 (로그 노이즈만 발생, 기능 영향 없음)
---
## 교훈
### uvloop + gRPC 조합 주의
- uvloop은 asyncio보다 빠르지만 gRPC와 호환성 이슈 존재
- 교훈: 성능 라이브러리 도입 시 의존성 충돌 사전 검증
### 로그 레벨 관리
- ERROR 레벨 로그가 실제 오류가 아닐 수 있음
- 교훈: 외부 라이브러리 로그는 필요 시 레벨 조정
### 일시적 오류 vs 치명적 오류
- BlockingIOError [Errno 11]은 일시적 리소스 부족으로 재시도 가능
- 교훈: 오류 코드와 영향 범위 구분 필요