diff --git a/journey/plans/260214_calendar_skill_자동_휴일감지_행동제어_구축.md b/journey/plans/260214_calendar_skill_자동_휴일감지_행동제어_구축.md new file mode 100644 index 0000000..89fc7ba --- /dev/null +++ b/journey/plans/260214_calendar_skill_자동_휴일감지_행동제어_구축.md @@ -0,0 +1,66 @@ +# Calendar Skill 기반 자동 휴일 감지 행동 제어 시스템 구축 + +**날짜**: 2026-02-14 +**작성자**: happybell80 +**관련 서비스**: rb8001, skill-calendar, robeing-monitor + +--- + +## 1. 문제 +- 스케줄러는 `mon-fri` cron 기준으로만 실행되어 공휴일을 배제하지 못한다. +- 연휴 중에도 평일 잡이 실행되어 운영 정책과 충돌한다. +- 현재 연휴 제어는 수동 비활성화에 의존한다. + +## 2. 목표 +- 목표 1: 상시 규칙으로 워킹데이(공휴일 제외) 실행을 자동화한다. +- 목표 2: 특정 기간(예: 설 연휴) 블랙아웃으로 즉시 실행 차단을 지원한다. +- 목표 3: 운영 API에서 상태 조회와 제어 이력을 확인한다. + +## 3. 해결방안 +- `skill-calendar`에 휴일 판정 API를 추가한다. +- `rb8001` 스케줄러 실행 경로에 공통 가드를 추가한다. +- DB에 스케줄 정책 필드를 추가하고 잡별 정책을 저장한다. +- `robeing-monitor` 설정 API에서 `schedule_type`, `schedule_days`를 실제 저장/조회로 전환한다. + +## 4. 아키텍처 +- 휴일 소스: Google Calendar의 공휴일 캘린더 + 수동 블랙아웃 기간. +- 판정 서비스: `skill-calendar`가 날짜별 `is_workday`, `is_blackout`, `reason`을 반환. +- 실행 가드: `rb8001` 잡 실행 직전 판정 API 호출 후 실행/스킵 결정. +- 운영 가시성: 스킵 로그를 activity 로그에 저장하고 모니터링 API로 조회. + +## 5. Phase 작업 +### Phase 1: 데이터 모델 +- `scheduled_jobs`에 `schedule_policy` JSONB 컬럼을 추가한다. +- 기본 정책을 `{"mode":"workday","blackout_ranges":[]}`로 저장한다. +- Repository CRUD에서 `schedule_policy` 읽기/쓰기/수정 경로를 추가한다. + +### Phase 2: skill-calendar 휴일 판정 +- `skill-calendar`에 `GET /api/workday/check` 엔드포인트를 추가한다. +- 입력: `date`, `timezone`, `country`, `blackout_ranges`. +- 출력: `is_workday`, `is_blackout`, `should_run`, `reason`. +- 결과 캐시를 1일 단위로 저장해 반복 조회 부하를 줄인다. + +### Phase 3: rb8001 실행 가드 +- `db_loader`에서 잡 등록 시 policy를 실행 함수 인자로 전달한다. +- 각 `_run_*_with_logging` 진입점에서 공통 가드 함수를 먼저 호출한다. +- `should_run=false`면 작업 본문을 실행하지 않고 스킵 로그를 남긴다. + +### Phase 4: 운영 API/관리 UI 정합화 +- `rb8001 /api/scheduler/jobs` 응답에 `schedule_policy`를 포함한다. +- `rb8001 /api/scheduler/jobs/{name}` PATCH에 `schedule_policy` 업데이트를 포함한다. +- `robeing-monitor` preferences API에서 `schedule_type`, `schedule_days`를 DB 반영한다. + +### Phase 5: 테스트/검증 +- 단위 테스트: 휴일/평일/블랙아웃 케이스 판정 테스트. +- 통합 테스트: 잡 실행 시 스킵/실행 분기 테스트. +- 운영 검증: 연휴 날짜(2026-02-16~2026-02-18) `should_run=false` 확인. + +## 6. 기대효과 +- 연휴/공휴일 기간의 자동 실행 충돌을 제거한다. +- 수동 비활성화 절차를 상시 자동 제어로 대체한다. +- 정책 기반 운영으로 스케줄 변경 이력과 실행 근거를 명확히 유지한다. + +## 7. 남은 작업 +- Phase 1~5를 순차 구현한다. +- 구현 완료 시 본 문서를 `journey/plans/archive/`로 이동한다. +- 상세 구현/장애 내역은 `journey/troubleshooting/`에 분리 기록한다. diff --git a/journey/troubleshooting/260214_scheduler_holiday_blackout_manual_pause.md b/journey/troubleshooting/260214_scheduler_holiday_blackout_manual_pause.md new file mode 100644 index 0000000..bcfade9 --- /dev/null +++ b/journey/troubleshooting/260214_scheduler_holiday_blackout_manual_pause.md @@ -0,0 +1,29 @@ +# 설 연휴 전 스케줄러 잡 일시 정지 처리 + +**날짜**: 2026-02-14 +**작성자**: happybell80 +**관련 파일**: `rb8001/app/router/scheduler_endpoint.py`, `rb8001/app/state/scheduler_repository.py`, `rb8001/app/scheduler/db_loader.py` + +--- + +## 문제 상황 +- 설 연휴(2026-02-16~2026-02-18) 기간에는 워킹데이 자동 작업을 중지해야 한다. +- 현재 스케줄은 `mon-fri` cron 기반이며 공휴일/연휴를 자동 판정하지 않는다. +- 연휴 전 즉시 중지를 위해 운영 API로 활성 잡을 전부 비활성화했다. + +## 해결 방안 +- `GET /api/scheduler/jobs`로 활성 잡 목록 확인 후 7개 잡 식별. +- 각 잡에 `PATCH /api/scheduler/jobs/{name}` + `{"enabled": false}` 적용. +- 적용 대상: `coldmail_daily`, `companyx_news`, `daily_diary`, `daily_headlines`, `dividend_collector`, `naverworks_daily`, `valuation_premia_recalculator`. +- 검증 1: `GET /api/scheduler/jobs` 결과 `{"total":0,"jobs":[]}` 확인. +- 검증 2: `GET /api/schedule/list` 결과 내부 상태 점검 잡(`scheduler_status_check`)만 남음 확인. +- 검증 3: `docker logs rb8001 --tail 80`에서 7개 잡 `Removed job ...` 로그 확인. + +## 구현 완료 +- 2026-02-14 14:26 KST, 운영 API 호출로 스케줄러 업무 잡 일시 정지 완료. +- 서비스 상태: `rb8001` 컨테이너 `healthy` 유지. + +## 교훈 +- `mon-fri`는 공휴일을 배제하지 못하므로 연휴 운영 요구를 충족하지 못한다. +- 연휴 운영은 즉시 차단(블랙아웃) 기능과 상시 워킹데이 판정 기능을 분리해 설계해야 한다. +- 연휴 직전 대응은 API 기반 일괄 비활성화 절차를 표준화하면 재현 가능성이 높아진다.