DOCS/journey/troubleshooting/250920_stats_api_unification_complete.md
Claude-51124 22557e7132 docs: 오래된 트러블슈팅 아카이브 및 구조 정리
- 7-8월 초기 구축 문서 12개를 _archive/troubleshooting/2025_07-08_initial_setup/로 이동
- book/300_architecture/390_human_in_the_loop_intent_learning.md를 journey/research/intent_classification/로 이동 (개발 여정 문서)
- 빈 폴더 제거 (journey/assets/*)
2025-11-17 14:06:05 +09:00

5.5 KiB

Stats API 일원화 구현 완료

개요

  • 일시: 2025-09-20
  • 작업자: Claude Code
  • 목표: rb8001과 robeing-monitor의 중복된 Stats API를 robeing-monitor로 일원화
  • 결과: 성공

문제 상황

1. 중복 구현

  • rb8001: 자체 stats 관리 (/stats, /api/stats/{robeing_id})
  • robeing-monitor: 별도 stats 관리 (/api/stats/{robeing_id})
  • 두 서비스가 동일한 DB 테이블(robeing)을 다른 스키마로 접근

2. 스키마 불일치

  • rb8001 ORM 모델: robeing_id 필드 (실제 DB에 없음)
  • robeing-monitor ORM 모델: robeing_container_id 필드 (실제 DB와 일치)
  • 실제 DB 테이블: UUID primary key, robeing_container_id 사용

3. 데이터 불일치 위험

  • 두 서비스가 독립적으로 stats 관리
  • 동일 테이블에 대한 경합 조건 발생 가능
  • 데이터 일관성 보장 불가

해결 방안

전략: robeing-monitor를 단일 소스로 통합

robeing-monitor가 이미 실제 DB 스키마와 일치하고, 여러 서비스에서 사용 가능하므로 Stats 관리의 단일 소스로 지정

구현 내용

1. rb8001 환경변수 설정

# /home/admin/ivada_project/rb8001/.env
STATE_SERVICE_URL=http://localhost:9024

2. rb8001 /stats 엔드포인트 수정

# main.py
@app.get("/stats")
async def get_stats():
    """현재 로빙의 스탯 조회 - robeing-monitor에서 가져옴"""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{settings.STATE_SERVICE_URL}/api/stats/{settings.ROBEING_ID}",
                timeout=5.0
            )
            if response.status_code == 200:
                data = response.json()
                return {
                    "robeing_id": settings.ROBEING_ID,
                    "stats": {
                        "memory": data.get("memory", 10),
                        "compute": data.get("compute", 10),
                        "react": data.get("react", 10),
                        "empathy": data.get("empathy", 10),
                        "leadership": data.get("leadership", 10)
                    },
                    "level": data.get("level", 1)
                }

3. rb8001 초기화 로직 수정

# app/router/router.py
async def _load_stats_from_state(self):
    """State Service(robeing-monitor)에서 스탯 로드"""
    try:
        if not settings.STATE_SERVICE_URL:
            logger.warning("STATE_SERVICE_URL not configured")
            return

        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{settings.STATE_SERVICE_URL}/api/stats/{settings.ROBEING_ID}",
                timeout=5.0
            )

            if response.status_code == 200:
                data = response.json()
                from app.brain.stats_manager import RobeingStats
                self.stats = RobeingStats(
                    memory=data.get("memory", 10),
                    compute=data.get("compute", 10),
                    react=data.get("react", 10),
                    empathy=data.get("empathy", 10),
                    leadership=data.get("leadership", 10)
                )
                logger.info(f"Stats loaded from robeing-monitor: {self.stats}")

4. rb8001 중복 코드 제거

# app/state/state_service.py
# stats 관련 엔드포인트 주석 처리
# @app.get("/api/stats/{robeing_id}")
# @app.put("/api/stats/{robeing_id}")

5. robeing-monitor PUT 엔드포인트 활성화

# /home/admin/ivada_project/robeing-monitor/app/main.py
# State Service 엔드포인트 마운트 추가
app.mount("/api", state_service.app)

테스트 결과

1. GET 테스트

# robeing-monitor 직접 조회
curl http://localhost:9024/api/stats/rb8001
# 결과: {"memory": 10, "compute": 10, "react": 10, ...}

# rb8001 프록시 조회
curl http://localhost:8001/stats
# 결과: {"robeing_id": "rb8001", "stats": {...}, "level": 3}

2. PUT 테스트

# Stats 업데이트
curl -X PUT http://localhost:9024/api/stats/rb8001 \
  -H "Content-Type: application/json" \
  -d '{"memory": 15, "compute": 12}'

# rb8001에서 확인
curl http://localhost:8001/stats
# 결과: 업데이트된 값 반영 확인

효과

1. 데이터 일관성

  • 단일 소스(robeing-monitor)에서만 stats 관리
  • 데이터 불일치 문제 해결

2. 유지보수성

  • 중복 코드 제거
  • 명확한 책임 분리

3. 확장성

  • 다른 서비스도 robeing-monitor API 사용 가능
  • 중앙 집중식 stats 관리

주의사항

  1. DB 스키마: 실제 테이블은 robeing_container_id 사용 (not robeing_id)
  2. Primary Key: UUID 타입 (not Integer)
  3. 환경변수: STATE_SERVICE_URL 필수 설정
  4. 의존성: robeing-monitor 서비스가 먼저 실행되어야 함

교훈

  1. DB 스키마 우선 확인: ORM 모델 작성 전 실제 테이블 구조 확인 필수
  2. 서비스 책임 명확화: 동일 기능 중복 구현 방지
  3. API 경로 일관성: GET과 PUT이 동일한 경로 패턴 사용하도록 설계
  4. 통합 테스트 중요성: 단순 조회뿐만 아니라 업데이트 기능도 테스트

관련 파일

  • /home/admin/ivada_project/rb8001/main.py
  • /home/admin/ivada_project/rb8001/app/router/router.py
  • /home/admin/ivada_project/rb8001/app/state/state_service.py
  • /home/admin/ivada_project/robeing-monitor/app/main.py
  • /home/admin/ivada_project/robeing-monitor/app/state/state_service.py