트러블슈팅 문서 업데이트 - Slack 이벤트 무한루프 및 중복 처리 해결

- 스킬 시스템 HTTP 분리 및 마이크로서비스 전환 완료
- Slack 이벤트 처리 무한루프 문제 해결
- EventCache 서비스로 중복 처리 방지
- 봇 메시지 필터링 3중 체크 구현
- 비동기 응답 순서 보장 메커니즘 추가
- 이메일 포함 메시지 필터링 문제 해결

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
happybell80 2025-07-22 01:38:00 +09:00
parent 0cd5f448f0
commit 2d1352fe18

View File

@ -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이 이메일을 `<mailto:...>` 형식으로 변환
- 기존 텍스트 기반 중복 체크가 유사한 패턴을 중복으로 판단
- 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. "큰 그림"보다 "작동하는 코드"가 우선 1. "큰 그림"보다 "작동하는 코드"가 우선
2. 복잡한 아키텍처보다 심플한 해결책이 때로는 최선 2. 복잡한 아키텍처보다 심플한 해결책이 때로는 최선
3. 프로토타입 단계에서는 과도한 설계 지양 3. 프로토타입 단계에서는 과도한 설계 지양
4. 아키텍처 원칙을 지키는 것이 결국 더 빠른 개발
5. 이벤트 처리에서는 공식 event_id 사용이 텍스트 기반보다 정확
6. 디버깅 로그는 문제 발생 시점에 미리 추가해야 효과적