[DB-01] 내구성 수집 cycle·09:00 SLA 스키마 마이그레이션

작업 내용 (설계 의도)

변경 사항

근거 설계: 20260730-확장-안전-공고수집-배치-design-db.md20260730-확장-안전-공고수집-배치-tdd.md.

Flyway expand-only migration으로 다음 MySQL 8 테이블과 쿼리 근거 인덱스를 추가한다.

  • job_posting_collection_cycles: (job_source_id, run_date) 유일 daily execution SSOT. NOT_STARTED/PENDING/RUNNING/SUCCESS/FAILED/BUDGET_EXHAUSTED 상태, cursor, lease, budget/count, completion 정보를 보관한다. CANCELLED 값은 만들지 않는다.
  • job_posting_collection_seen_postings: cycle 내부 source job ID 멱등 집합과 terminal final-delta 입력이다.
  • external_request_host_limits: 다중 인스턴스 host별 요청 간격의 DB state다.
  • job_posting_collection_sla_snapshots: 00:00에 생성하는 날짜 유일 09:00 cutoff gate다. PENDING/CAPTURING/CAPTURED/MISSED/NOT_APPLICABLE만 허용값으로 문서화하며, MISSED는 item/count를 저장하지 않는 불변 상태다.
  • job_posting_collection_sla_snapshot_sources: CAPTURED cutoff의 source별 immutable cycle status/count/abnormal/closeGuarded snapshot이다.

기존 job_posting_collection_runs는 변경하지 않는다. v2에서 cursor/lease/claim의 SSOT는 새 cycle 테이블이고, 기존 run은 terminal compatibility projection으로만 계속 사용한다.

모든 테이블/컬럼 COMMENT, DATETIME(6), TINYINT(1), VARCHAR 상태값, id PK, FK 없음, JSON 없음 규약을 지킨다. 인덱스는 cycle ready claim/lease expiry/terminal seen cleanup, seen 48시간 metric, host permit, SLA date gate, snapshot item status query에 한정한다. Flyway에는 대량 백필 DML을 넣지 않는다.

롤백: migration 적용 또는 dark deploy 전에는 새 테이블을 역순 drop할 수 있다. activation 이후에는 역방향 DROP을 하지 않고 posting.collection-dispatch-v2 및 SLA/notification scheduler를 OFF해 코드만 rollback한다. 새 테이블은 기존 binary가 무시하므로 additive 상태로 남겨도 안전하다.

의존

  • 없음 — DB schema 공통 선행 병목

다이어그램

처리 흐름

sequenceDiagram
    participant F as Flyway
    participant M as MySQL 8
    participant L as Legacy scheduler
    participant V as V2 dispatcher
    F->>M: create expand-only tables/indexes
    L->>M: write existing collection runs
    V->>M: write cycles, seen, throttle, SLA gate
    M-->>V: unique/lease/index guarantees

클래스 의존

flowchart LR
    CycleRepository --> Cycles[(collection cycles)]
    CycleRepository --> Seen[(seen postings)]
    ThrottleRepository --> Hosts[(host limits)]
    SlaRepository --> SlaHeader[(SLA snapshots)]
    SlaRepository --> SlaItems[(SLA snapshot sources)]
    LegacyRepository --> Runs[(collection runs)]

테스트 케이스

  • baseline migration 다음 DB-01 migration이 MySQL 8에서 exit code 0으로 적용되고 모든 신규 테이블·컬럼 COMMENT가 존재한다.
  • job_posting_collection_cycles(job_source_id, run_date)와 SLA header의 snapshot_date unique key가 각각 중복 insert를 거부한다.
  • cycle ready/lease-expiry, seen (cycle_id, source_job_id), host unique, SLA item (snapshot_id, job_source_id) 인덱스가 설계의 대상 쿼리를 사용 가능하게 만든다.
  • SLA header와 item 스키마가 CAPTURED immutable item 및 MISSED item 0행/null count API 계약을 표현할 수 있고 CANCELED 계열 상태값을 도입하지 않는다.
  • 기존 job_posting_collection_runs의 legacy SUCCESS/FAILED row를 신규 migration 전후로 동일하게 읽을 수 있다.
  • activation 이후 rollback은 새 테이블 DROP 없이 flag/scheduler OFF만으로 구 binary가 기동 가능하다.