| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 |
- using System.ComponentModel.DataAnnotations;
- namespace Domain.Entities.Stocks;
- /// <summary>
- /// SEIBro per-키 rolling 수집의 "조회 시도" 마커 (자연키 UNIQUE (JobKey, EntityKey)) — SEIBro 통합 리뷰 결함 #1 해소용.
- /// 완료 판정을 "대상/자식 테이블에 행이 있으면 수집됨"으로 하면, 정상적으로 0행을 반환하는 API(getIntPayInfo·getCDInfo 등)의 키가
- /// 매 실행 최우선 재조회되어 나머지 유니버스가 굶는다(starvation, resumable 붕괴). 이 마커는 조회를 시도할 때마다(0행이어도)
- /// LastCheckedAt 을 스탬핑하고, rolling 대상 선정을 "데이터 존재"가 아닌 "이 마커의 LastCheckedAt(없으면 최우선 → 오래된 순)"으로
- /// 정렬하게 한다. 스키마 오염 없이 전 rolling job 에 일관 적용하려고 마스터/대상 엔티티가 아닌 공용 테이블로 둔다.
- /// JobKey = job 식별자(예 "bond-intpay", "bond-cd"), EntityKey = 대상 키 문자열(ISIN·회사번호 등, 복합키는 구분자로 결합).
- /// </summary>
- public class SeibroFetchMarker
- {
- [Key]
- public int ID { get; private set; }
- /// <summary>수집 job 식별자 (예 "bond-intpay", "deriv-master", "corp-meeting")</summary>
- public string JobKey { get; private set; } = default!;
- /// <summary>대상 키 (ISIN·발행회사번호 등, 복합키는 배치가 구분자로 결합해 전달)</summary>
- public string EntityKey { get; private set; } = default!;
- /// <summary>마지막 조회 시도 시각 (UTC) — 0행이어도 갱신. rolling 대상 정렬 기준.</summary>
- public DateTime LastCheckedAt { get; private set; } = DateTime.UtcNow;
- private SeibroFetchMarker() { }
- public static SeibroFetchMarker Create(string jobKey, string entityKey)
- {
- if (string.IsNullOrWhiteSpace(jobKey))
- {
- throw new ArgumentException("jobKey required", nameof(jobKey));
- }
- if (string.IsNullOrWhiteSpace(entityKey))
- {
- throw new ArgumentException("entityKey required", nameof(entityKey));
- }
- return new SeibroFetchMarker
- {
- JobKey = jobKey.Trim(),
- EntityKey = entityKey.Trim(),
- LastCheckedAt = DateTime.UtcNow
- };
- }
- /// <summary>조회 시도 시각을 현재로 스탬핑 (0행 응답 포함, 매 조회마다 호출)</summary>
- public void Touch()
- {
- LastCheckedAt = DateTime.UtcNow;
- }
- }
|