3.4 KiB
3.4 KiB
9시 네이버 이메일 분석 미전송과 실패 은닉 해결
tags: [naverworks, email, briefing, scheduler, timeout, fallback]
날짜: 2026-03-09
작성자: Codex
관련 파일: rb8001/app/services/skills/naverworks_briefing.py, rb8001/app/scheduler/jobs/naverworks_briefing.py, skill-email/services/naverworks_provider.py
상위 원칙: 문서 작성 원칙, 백엔드 구조 원칙
관련 문서
문제 상황
2026-03-09 09:00:00KST에naverworks_daily작업은 실제 실행됐다.2026-03-09 09:00:30KST에rb8001 -> skill-email /messages호출이httpx.ReadTimeout으로 실패했다.- 그런데
rb8001/app/services/skills/naverworks_briefing.py:57경로가 이 실패를No emails처럼 처리해, 운영자가 "메일이 없었다"고 오인할 수 있는 상태가 됐다. rb8001/app/scheduler/jobs/naverworks_briefing.py:87도 예외를 다시 올리지 않아 스케줄러에는 성공처럼 남았다.
해결 방안
rb8001/app/services/skills/naverworks_briefing.py:16:BriefingFetchError를 추가해 메일 조회 실패를 빈 결과와 분리했다.rb8001/app/services/skills/naverworks_briefing.py:57: 실제 빈 목록일 때만No emails in the configured briefing window를 기록하도록 바꿨다.rb8001/app/services/skills/naverworks_briefing.py:109:httpx.ReadTimeout,httpx.HTTPError, 비정상 응답, 잘못된 payload를BriefingFetchError로 올리도록 바꿨다.rb8001/app/scheduler/jobs/naverworks_briefing.py:89: 스케줄러 래퍼가ImportError와 일반 예외를 다시 올려 APScheduler가 실패로 기록하게 바꿨다.skill-email/services/naverworks_provider.py:38: 토큰 만료 판단 기준을datetime.utcnow()로 명시해 UTC naive DB 값과 비교 기준을 맞췄다.skill-email/services/naverworks_provider.py:49,skill-email/services/naverworks_provider.py:197,skill-email/services/naverworks_provider.py:357: 컨텍스트 조회, 외부 NAVER WORKS API 호출, refresh 호출에 단계별 추적 로그와 timeout 분기 로그를 추가했다.
검증
docker exec -e PYTHONPATH=/code rb8001 pytest -q tests/test_naverworks_briefing.py결과10 passedhttps://ro-being.com/rb8001/health응답200https://ro-being.com/skill-email/health응답200skill-email /messages재호출 시200응답과 단계별 로그(context lookup,token state,API request finished)를 확인했다.
구현 완료
rb8001커밋:6b2280e(fix: surface naverworks briefing failures)skill-email커밋:7a57aae(fix: add naverworks fetch tracing)
교훈
- 외부 API 조회 실패와 "실제 0건"은 같은 값으로 처리하면 안 된다.
- 스케줄러 성공 로그는 실제 작업 성공과 같지 않으므로, 예외를 다시 올려 관측 가능한 실패로 남겨야 한다.
- 시간대가 섞인 토큰 만료 판단은 장애를 숨기기 쉬우므로, DB 타입과 비교 기준을 같은 시간 축으로 맞춰야 한다.