diff --git a/docs/troubleshooting/250721_happybell80_로빙기억력문제및nginx포트추가.md b/docs/troubleshooting/250721_happybell80_로빙기억력문제및nginx포트추가.md index 606d00e..232d03a 100644 --- a/docs/troubleshooting/250721_happybell80_로빙기억력문제및nginx포트추가.md +++ b/docs/troubleshooting/250721_happybell80_로빙기억력문제및nginx포트추가.md @@ -118,7 +118,138 @@ if history: --- +## 오후 11시 54분 + +### 스킬 시스템 HTTP 분리 및 이메일 스킬 마이크로서비스 전환 + +**문제 상황**: +- rb10508_test의 email_skill이 직접 import하며 인증 오류 발생 +- 함수형 프로그래밍 시도가 비동기 문제로 복잡해짐 +- 로빙과 스킬의 강한 결합 + +**아키텍처 문제**: +- 로빙 철학: 스킬은 로빙 컨테이너 외부에 독립적으로 존재해야 함 +- 현재: skill_email을 직접 import하여 사용 (아키텍처 위반) +- 목표: HTTP API로 완전 분리 + +**해결 과정**: + +1. **skill_email 서비스화**: + - main.py로 FastAPI 서버 구현 (포트 8501) + - `/send`, `/messages`, `/health` 엔드포인트 제공 + - 독립 실행: `python main.py` + +2. **rb10508_test 수정**: + - email_skill.py를 HTTP 클라이언트로 단순화 (111줄 → 57줄) + - sys.path 조작 제거, 직접 import 제거 + - httpx로 API 호출만 수행 + +3. **Nginx 프록시 설정**: + ```nginx + location /skill-email/ { + proxy_pass http://localhost:8501/; + } + ``` + +4. **Docker 설정 정리**: + - volume mount 제거 (불필요) + - 환경변수로 SKILL_EMAIL_URL 전달 + +**주요 교훈**: +- "빠른 개발"이라며 아키텍처 원칙 무시하면 더 복잡해짐 +- 마이크로서비스는 처음부터 HTTP로 분리하는 것이 정답 +- 로빙 철학: 스킬은 외부 서비스, 로빙은 클라이언트 + +**결과**: +- 완전한 HTTP 분리 달성 +- 인증 문제 해결 (각 서비스가 독립적으로 관리) +- 확장성 확보 (다른 로빙도 같은 스킬 사용 가능) + +--- + +--- + +## 새벽 01시 30분 + +### Slack 이벤트 처리 무한루프 및 중복 처리 문제 해결 + +**문제 발견**: +1. **무한루프**: 로빙이 자기 메시지를 다시 처리하여 계속 응답 +2. **중복 처리**: 같은 멘션 메시지가 app_mention/message 두 번 처리됨 +3. **비동기 순서 문제**: "답변 생성중" 메시지가 실제 답변보다 8초 늦게 도착 + +**해결 과정**: + +1. **SlackService 봇 ID 동적 획득** (25-31줄): +```python +try: + bot_info = self.client.auth_test() + self.bot_user_id = bot_info.get('user_id') + logger.info(f"Bot user ID: {self.bot_user_id}") +except Exception as e: + self.bot_user_id = None +``` + +2. **EventCache 서비스 신규 생성** (`event_cache.py`): + - 10분 TTL로 event_id 기반 중복 체크 + - 메모리 기반 캐시로 Redis 없이 구현 + - 주기적 만료 항목 정리 기능 + +3. **3중 봇 메시지 필터링** (slack.py 76-80줄): +```python +if (bot_id or + (slack_service.bot_user_id and event_user == slack_service.bot_user_id) or + subtype == "bot_message"): + return JSONResponse({"status": "bot_message_ignored"}) +``` + +4. **비동기 응답 순서 보장** (124-132줄): + - 즉시 "🤔 답변 생성중..." 전송 + - 0.1초 대기로 Slack API 순서 보장 + - 백그라운드 처리 완료 후 "✅ 실제답변" 전송 + +5. **message 이벤트 처리 추가** (94줄): + - 기존 app_mention만 처리 → app_mention + message 처리 + - 멘션 없는 직접 대화도 처리 가능 + +**추가 발견된 문제**: + +### 이메일 주소 포함 메시지 필터링 문제 + +**증상**: +- `goeun2dc@gmail.com으로 전송해줘` → 정상 처리 +- 이후 이메일 내용 전송 → 완전 무반응 +- "?", "로빙?" 등 후속 메시지 → 모두 무반응 + +**원인 분석**: +- Slack이 이메일을 `` 형식으로 변환 +- 기존 텍스트 기반 중복 체크가 유사한 패턴을 중복으로 판단 +- event_id 체크 전에 이미 차단됨 + +**해결**: +- 기존 `processed_events` 텍스트 기반 중복 체크 완전 제거 +- event_id 기반 중복 체크만 유지 +- 이메일 포함 메시지도 정상 처리됨 + +### 봇 필터링 오작동 문제 (진행 중) + +**증상**: +- 16:19 첫 메시지 정상 처리 +- 16:20 이후 모든 메시지가 `bot_message_ignored`로 차단 + +**추가한 디버깅**: +```python +logger.debug(f"Bot filter check - user: {event_user}, bot_user_id: {slack_service.bot_user_id}, bot_id: {bot_id}, subtype: {subtype}") +``` + +**대기 중**: 서버 로그에서 실제 필터링 값들 확인 필요 + +--- + **교훈**: 1. "큰 그림"보다 "작동하는 코드"가 우선 2. 복잡한 아키텍처보다 심플한 해결책이 때로는 최선 -3. 프로토타입 단계에서는 과도한 설계 지양 \ No newline at end of file +3. 프로토타입 단계에서는 과도한 설계 지양 +4. 아키텍처 원칙을 지키는 것이 결국 더 빠른 개발 +5. 이벤트 처리에서는 공식 event_id 사용이 텍스트 기반보다 정확 +6. 디버깅 로그는 문제 발생 시점에 미리 추가해야 효과적 \ No newline at end of file