From ef39716c192ced44f635ef8ef221a011dfe5e79d Mon Sep 17 00:00:00 2001 From: happybell80 Date: Mon, 25 Aug 2025 00:18:19 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20DB=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=8F=20rb8001=20=ED=81=AC=EB=A1=A0=EC=9E=A1=20=ED=8A=B8?= =?UTF-8?q?=EB=9F=AC=EB=B8=94=EC=8A=88=ED=8C=85=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tables.md: 실제 DB 구조에 맞게 수정 - gmail_tokens 테이블 추가 컬럼 반영 (access_token, refresh_token 등) - robeing_stats 테이블 컬럼 수정 (email_sent_count 제거, name 추가) - 테이블 소유자 정보 업데이트 - gmail_tokens_old 백업 테이블 문서화 - rb8001 일일 요약 크론잡 실패 분석 문서 신규 작성 - Gateway-rb8001-skill 서비스 간 플로우 문서화 - skill-email 500 에러 원인 분석 (auth_db 부재) - 해결 방안 및 모니터링 포인트 제시 --- 300_architecture/database/tables.md | 28 +- ...50824_rb8001_daily_summary_cron_failure.md | 254 ++++++++++++++++++ 2 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 troubleshooting/250824_rb8001_daily_summary_cron_failure.md diff --git a/300_architecture/database/tables.md b/300_architecture/database/tables.md index 97bf8b2..e312a2a 100644 --- a/300_architecture/database/tables.md +++ b/300_architecture/database/tables.md @@ -1,7 +1,7 @@ # PostgreSQL 테이블 구조 ## 작성일: 2025-08-20 -## 최종 수정일: 2025-08-23 +## 최종 수정일: 2025-08-24 ## 데이터베이스: main_db --- @@ -109,6 +109,7 @@ ### gmail_tokens - **용도**: Gmail OAuth 토큰 저장 - **Primary Key**: id (SERIAL) +- **소유자**: robeings | 컬럼명 | 타입 | NULL | 기본값 | 설명 | |--------|------|------|--------|------| @@ -117,19 +118,24 @@ | username | VARCHAR(50) | YES | | 사용자명 (users.username과 동일) | | slack_id | VARCHAR(50) | YES | | Slack User ID (U로 시작) | | robeing_id | VARCHAR(50) | YES | | 로빙 ID | -| token_data | JSONB | NO | | access_token, refresh_token, token_type 등 | +| token_data | JSONB | YES | | access_token, refresh_token, token_type 등 | | oauth_config | JSONB | YES | | client_id, client_secret, token_uri | | scopes | JSONB | YES | | Gmail API 권한 목록 | | metadata | JSONB | YES | | email, name, picture, verified_email 등 | | expiry | TIMESTAMP | YES | | 토큰 만료 시각 | | is_equipped | BOOLEAN | YES | false | 장착 상태 | | equipped_to | VARCHAR(50) | YES | | 장착된 로빙 ID | +| access_token | TEXT | YES | | 직접 저장된 액세스 토큰 | +| refresh_token | TEXT | YES | | 직접 저장된 리프레시 토큰 | +| token_type | VARCHAR | YES | 'Bearer' | 토큰 타입 | +| expires_at | DOUBLE PRECISION | YES | | 토큰 만료 시간 (Unix timestamp) | | created_at | TIMESTAMP | YES | CURRENT_TIMESTAMP | 생성 시각 | | updated_at | TIMESTAMP | YES | CURRENT_TIMESTAMP | 수정 시각 | ### gmail_audit_logs - **용도**: Gmail 아이템 작업 감사 로그 - **Primary Key**: id (SERIAL) +- **소유자**: postgres (권한 조정 필요) | 컬럼명 | 타입 | NULL | 기본값 | 설명 | |--------|------|------|--------|------| @@ -141,6 +147,16 @@ | details | JSONB | YES | | 상세 정보 | | created_at | TIMESTAMP | YES | CURRENT_TIMESTAMP | 생성 시각 | +### gmail_tokens_old +- **용도**: gmail_tokens 테이블 백업 (마이그레이션 과정 중 생성) +- **Primary Key**: id (SERIAL) +- **소유자**: robeings +- **참고**: 이전 구조의 백업 테이블로, 향후 제거 가능 + +| 컬럼명 | 타입 | NULL | 기본값 | 설명 | +|--------|------|------|--------|------| +| (구조는 gmail_tokens와 유사하나 이전 버전) | | | | 마이그레이션 전 데이터 보관용 | + --- ## 5. 로빙 관련 테이블 @@ -148,15 +164,16 @@ ### robeing_stats - **용도**: 로빙 통계 및 레벨 정보 - **Primary Key**: id (SERIAL) +- **소유자**: postgres (권한 조정 필요) | 컬럼명 | 타입 | NULL | 기본값 | 설명 | |--------|------|------|--------|------| | id | SERIAL | NO | | 통계 ID | | user_id | UUID | YES | | 사용자 ID (FK → users) | -| robeing_id | VARCHAR(50) | YES | | 로빙 ID | +| robeing_id | VARCHAR(50) | NO | | 로빙 ID (UNIQUE) | +| name | VARCHAR(100) | YES | | 로빙 이름 | | level | INTEGER | YES | 1 | 현재 레벨 | | experience | INTEGER | YES | 0 | 경험치 | -| email_sent_count | INTEGER | YES | 0 | 이메일 발송 횟수 | | created_at | TIMESTAMP | YES | CURRENT_TIMESTAMP | 생성 시각 | | updated_at | TIMESTAMP | YES | CURRENT_TIMESTAMP | 수정 시각 | @@ -277,7 +294,10 @@ ### 개선 필요 사항 1. 일부 테이블의 소유자가 postgres로 되어있어 권한 조정 필요 + - gmail_audit_logs: postgres → robeings + - robeing_stats: postgres → robeings 2. auth_db → main_db로 마이그레이션 완료 +3. gmail_tokens_old 백업 테이블 정리 검토 --- diff --git a/troubleshooting/250824_rb8001_daily_summary_cron_failure.md b/troubleshooting/250824_rb8001_daily_summary_cron_failure.md new file mode 100644 index 0000000..9c4b6a4 --- /dev/null +++ b/troubleshooting/250824_rb8001_daily_summary_cron_failure.md @@ -0,0 +1,254 @@ +# rb8001 일일 요약 크론잡 실패 분석 + +## 작성일: 2025-08-24 +## 작성자: 서버 관리자 with Claude +## 영향 서버: 51123(Gateway) → 51124(rb8001, skill-email) + +--- + +## 1. 문제 개요 + +### 1.1 증상 +- **발생 시간**: 매일 오전 9시 (KST) +- **영향**: 사용자들에게 불완전한 모닝 브리핑 전송 (이메일 요약 누락) +- **대상 사용자**: + - 전희재 (U091UNVE41M) + - 김종태 (U0925SXQFDK) + - HanYong Hwang (U092F7FQ55L) + +### 1.2 에러 메시지 +``` +Gmail token not ready for user U091UNVE41M: reauth_required +500 Internal Server Error from skill-email service +``` + +--- + +## 2. 시스템 아키텍처 + +### 2.1 크론잡 구성 (51123 서버) +```bash +# Gateway 컨테이너 내부 크론탭 +0 9 * * * curl -X POST http://192.168.219.52:8001/api/cron/daily-summary \ + -H "Content-Type: application/json" \ + 2>/dev/null || true # briefing +``` + +### 2.2 네트워크 플로우 +``` +[51123 Gateway 크론] + ↓ POST 요청 +[51124 rb8001:8001] + ↓ 데이터 수집 (병렬) + ├→ skill-news:8505 (뉴스 검색) ✅ + ├→ skill-email:8501 (이메일 조회) ❌ 500 에러 + └→ rb10508_micro (LLM 요약) ✅ + ↓ +[Slack API → 사용자 DM] +``` + +### 2.3 인증 체계 +- **엔드포인트**: `/api/cron/daily-summary` +- **인증 토큰**: Bearer cron-secret-2024 +- **실행 주체**: Gateway 컨테이너 (51123) + +--- + +## 3. 근본 원인 분석 + +### 3.1 skill-email 서비스 실패 (51124 서버) + +#### 데이터베이스 연결 문제 +```python +# skill-email 환경 설정 +TOKEN_PROVIDER=database +DATABASE_URL=postgresql://robeings:robeings@localhost:5433/auth_db +``` + +**문제점**: +1. **auth_db 부재**: 51123 서버에 auth_db 데이터베이스 없음 (main_db만 존재) +2. **SSH 터널 설정**: 5433 포트가 51123으로 포워딩되나 DB 자체가 없음 +3. **토큰 조회 실패**: DBCredentialsProvider가 연결 실패로 토큰 조회 불가 + +#### 에러 체인 +``` +1. rb8001 → skill-email API 호출 (/messages?user_id=U091UNVE41M) +2. skill-email → PostgreSQL 연결 시도 (auth_db) +3. PostgreSQL → "database 'auth_db' does not exist" 에러 +4. skill-email → "reauth_required" 폴백 응답 +5. rb8001 → 500 Internal Server Error 수신 +``` + +### 3.2 추가 이슈 + +#### datetime import 누락 +```python +# rb8001/main.py 에러 +NameError: name 'datetime' is not defined +``` + +#### 슬랙 워크스페이스 불일치 +- **현재 등록**: T035VFRKCN6 (GoodGang Labs) +- **필요한 것**: T0925SXPS4D (미등록) + +--- + +## 4. 실행 프로세스 상세 + +### 4.1 정상 동작 시나리오 +1. **09:00:00** - Gateway 크론 트리거 +2. **09:00:01** - rb8001 `/api/cron/daily-summary` 호출 +3. **09:00:02** - 병렬 데이터 수집 시작 + - 뉴스: AI 키워드로 최신 뉴스 5개 + - 이메일: 사용자별 최근 이메일 5개 +4. **09:00:05** - LLM 요약 생성 +5. **09:00:07** - Slack DM 전송 + +### 4.2 현재 실패 시나리오 +1. **09:00:00** - Gateway 크론 트리거 ✅ +2. **09:00:01** - rb8001 엔드포인트 호출 ✅ +3. **09:00:02** - 데이터 수집 시작 + - 뉴스: 성공 ✅ + - 이메일: **실패** ❌ (500 에러) +4. **09:00:03** - 부분적 요약 생성 (뉴스만) +5. **09:00:04** - 불완전한 DM 전송 + +--- + +## 5. 해결 방안 + +### 5.1 즉시 조치 (임시) +```bash +# skill-email 환경 변경 (database → file 모드) +cd /home/admin/ivada_project/skill_email +vi .env +# TOKEN_PROVIDER=file 로 변경 + +# 서비스 재시작 +docker compose down && docker compose up -d --build +``` + +### 5.2 근본 해결 + +#### 옵션 1: auth_db → main_db 마이그레이션 +```bash +# skill-email .env 수정 +DATABASE_URL=postgresql://robeings:robeings@localhost:5433/main_db + +# gmail_tokens 테이블이 main_db에 이미 존재하므로 정상 작동 예상 +``` + +#### 옵션 2: 51123 서버 직접 연결 +```bash +# SSH 터널 대신 직접 연결 +DATABASE_URL=postgresql://robeings:robeings@192.168.219.45:5432/main_db +``` + +#### 옵션 3: rb8001 내장 이메일 기능 사용 +- rb8001에 이미 통합된 email_integration.py 활용 +- skill-email 의존성 제거 + +### 5.3 코드 수정 필요 +```python +# rb8001/main.py 상단에 추가 +import datetime + +# 또는 +from datetime import datetime +``` + +--- + +## 6. 검증 방법 + +### 6.1 수동 테스트 +```bash +# skill-email 직접 테스트 +curl -X GET http://localhost:8501/messages?user_id=U091UNVE41M \ + -H "Authorization: Bearer test-token" + +# rb8001 크론 엔드포인트 테스트 +curl -X POST http://localhost:8001/api/cron/daily-summary \ + -H "Authorization: Bearer cron-secret-2024" +``` + +### 6.2 로그 확인 +```bash +# skill-email 로그 +docker logs skill-email --tail 50 + +# rb8001 로그 +docker logs rb8001 --tail 50 + +# Gateway 로그 (크론 실행 확인) +docker exec robeing-gateway tail -f /var/log/cron.log +``` + +--- + +## 7. 모니터링 포인트 + +### 7.1 일일 체크리스트 +- [ ] 오전 9시 크론 실행 여부 +- [ ] skill-email 500 에러 발생 여부 +- [ ] Slack DM 정상 수신 여부 +- [ ] 이메일 요약 포함 여부 + +### 7.2 알람 설정 권장 +```bash +# 크론 실패 시 알람 +0 9 * * * curl ... || echo "Cron failed" | mail -s "Alert" admin@example.com +``` + +--- + +## 8. 교훈 및 개선사항 + +### 8.1 아키텍처 개선 +1. **환경 일관성**: 모든 서비스가 동일한 DB 사용 (main_db) +2. **의존성 최소화**: 단일 서비스 장애가 전체 기능 마비 방지 +3. **폴백 메커니즘**: 이메일 실패 시에도 기본 브리핑 전송 + +### 8.2 운영 개선 +1. **헬스체크 강화**: 각 마이크로서비스 상태 모니터링 +2. **에러 핸들링**: graceful degradation 구현 +3. **로그 중앙화**: 분산 서비스 로그 통합 관리 + +### 8.3 문서화 +1. **시스템 다이어그램**: 서비스 간 의존성 명확화 +2. **환경변수 문서**: 각 서비스별 필수 설정 문서화 +3. **트러블슈팅 가이드**: 일반적인 문제 해결 방법 정리 + +--- + +## 9. 관련 파일 + +### 51123 서버 +- `/home/admin/robeing-gateway/entrypoint.sh` - 크론 시작 +- `/home/admin/robeing-gateway/Dockerfile` - 크론 설치 + +### 51124 서버 +- `/home/admin/ivada_project/rb8001/main.py` - 크론 엔드포인트 +- `/home/admin/ivada_project/rb8001/app/cron/daily_summary.py` - 요약 로직 +- `/home/admin/ivada_project/skill_email/.env` - DB 설정 +- `/home/admin/ivada_project/skill_email/services/gmail_service.py` - Gmail 서비스 + +--- + +## 10. 현재 상태 (2025-08-24 23:50) + +### 확인 사항 +- **Gateway 크론**: 정상 작동 ✅ +- **rb8001 서비스**: 정상 작동 ✅ +- **skill-news**: 정상 작동 ✅ +- **skill-email**: 500 에러 ❌ +- **auth_db**: 존재하지 않음 ❌ +- **main_db gmail_tokens**: 정상 존재 ✅ + +### 긴급도 +- **높음**: 매일 오전 9시 사용자 영향 +- **권장 조치**: skill-email을 file 모드로 전환 또는 main_db 연결 + +--- + +**문서 끝** \ No newline at end of file