DOCS/journey/plans/260214_calendar_skill_자동_휴일감지_행동제어_구축.md
2026-03-10 22:56:31 +09:00

5.0 KiB

tags
tags
calendar
scheduler
holiday
blackout
plans

Calendar Skill 기반 자동 휴일 감지 행동 제어 시스템 구축

날짜: 2026-02-14 작성자: happybell80 관련 서비스: rb8001, skill-calendar, robeing-monitor

관련 문서


1. 문제

  • 스케줄러는 mon-fri cron 기준으로만 실행되어 공휴일을 배제하지 못한다.
  • 연휴 중에도 평일 잡이 실행되어 운영 정책과 충돌한다.
  • 현재 연휴 제어는 수동 비활성화에 의존한다.

1-1. 원인 확정

  • scheduled_jobs에 휴일/블랙아웃 정책 저장층이 없다.
  • skill-calendar에 휴일 판정 API가 없다.
  • rb8001 잡 실행 전에 공통 실행 가드가 없다.
  • robeing-monitorschedule_type, schedule_days는 실제 DB에 저장되지 않는다.

2. 목표

  • 목표 1: 상시 규칙으로 워킹데이(공휴일 제외) 실행을 자동화한다.
  • 목표 2: 특정 기간(예: 설 연휴) 블랙아웃으로 즉시 실행 차단을 지원한다.
  • 목표 3: 운영 API에서 상태 조회와 제어 이력을 확인한다.

2-1. 고정 결정

  • 대한민국 공휴일 1차 SSOT는 공공데이터포털 한국천문연구원 특일 정보 OpenAPI로 고정한다.
  • 1차 운영 범위는 country=KR, timezone=Asia/Seoul로 고정한다.
  • 잡 실행 정책 저장 위치는 scheduled_jobs.schedule_policy JSONB로 고정한다.
  • 실행 차단 위치는 각 _run_*_with_logging 진입점 앞 공통 가드 헬퍼로 고정한다.
  • db_loader는 정책 전달까지만 담당하고, 실행 여부 판정은 하지 않는다.

3. 해결방안

  • skill-calendar에 휴일 판정 API를 추가한다.
  • rb8001 스케줄러 실행 경로에 공통 가드를 추가한다.
  • DB에 스케줄 정책 필드를 추가하고 잡별 정책을 저장한다.
  • robeing-monitor 설정 API에서 schedule_type, schedule_days를 실제 저장/조회로 전환한다.

4. 아키텍처

  • 휴일 소스: 한국천문연구원 특일 정보 OpenAPI + 수동 블랙아웃 기간.
  • 판정 서비스: skill-calendar가 날짜별 is_workday, is_blackout, reason을 반환.
  • 실행 가드: rb8001 잡 실행 직전 판정 API 호출 후 실행/스킵 결정.
  • 운영 가시성: 스킵 로그를 activity 로그에 저장하고 모니터링 API로 조회.

5. Phase 작업

Phase 1: 데이터 모델

  • scheduled_jobsschedule_policy JSONB 컬럼을 추가한다.
  • 기본 정책을 {"mode":"workday","country":"KR","timezone":"Asia/Seoul","blackout_ranges":[]}로 저장한다.
  • Repository CRUD에서 schedule_policy 읽기/쓰기/수정 경로를 추가한다.

Phase 2: skill-calendar 휴일 판정

  • skill-calendarGET /api/workday/check 엔드포인트를 추가한다.
  • 입력: date, timezone, country, blackout_ranges.
  • 출력: is_workday, is_blackout, should_run, reason.
  • 응답 계약은 아래 최소 형태로 고정한다.
    • {"date":"YYYY-MM-DD","country":"KR","timezone":"Asia/Seoul","is_workday":bool,"is_blackout":bool,"should_run":bool,"reason":"holiday|blackout|workday|weekend"}
  • 결과 캐시를 1일 단위로 저장해 반복 조회 부하를 줄인다.

Phase 3: rb8001 실행 가드

  • db_loader에서 잡 등록 시 schedule_policy를 실행 함수 인자로 전달한다.
  • _run_*_with_logging 진입점에서 공통 가드 함수를 먼저 호출한다.
  • should_run=false면 작업 본문을 실행하지 않고 스킵 로그를 남긴다.
  • 스킵 로그 최소 필드는 아래로 고정한다.
    • job_name, job_type, scheduled_at, policy_mode, date, country, timezone, should_run, reason

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 확인.
  • 고정 테스트 케이스:
    • 2026-02-16 ~ 2026-02-18 -> should_run=false
    • 일반 평일 1건 -> should_run=true
    • 토요일 1건 -> should_run=false
    • 수동 블랙아웃 날짜 1건 -> should_run=false

6. 기대효과

  • 연휴/공휴일 기간의 자동 실행 충돌을 제거한다.
  • 수동 비활성화 절차를 상시 자동 제어로 대체한다.
  • 정책 기반 운영으로 스케줄 변경 이력과 실행 근거를 명확히 유지한다.

7. 남은 작업

  • Phase 1~5를 순차 구현한다.
  • 구현 완료 시 본 문서를 journey/plans/archive/로 이동한다.
  • 상세 구현/장애 내역은 journey/troubleshooting/에 분리 기록한다.