| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- using Application.Abstractions.Data;
- using Domain.Entities.Stocks;
- using Microsoft.EntityFrameworkCore;
- namespace Infrastructure.StockData;
- /// <summary>
- /// SEIBro 수집 마커(SeibroFetchMarker rolling · SeibroSweptDate date-sweep) 조회/upsert 헬퍼 — 리뷰 결함 #1 해소 배선의 공용 경로.
- /// 각 SyncService 가 완료 판정을 "데이터 행 존재"에서 "조회 시도(0행 포함) 마커 존재"로 바꾸는 데 쓴다.
- /// • rolling: LoadFetchMarkers 로 (키→마지막조회시각) 사전을 만들어 rolling 대상을 정렬(미조회 최우선→오래된 순), fetch 후 TouchFetchMarker.
- /// • date-sweep: IsSwept 로 "데이터 존재 OR 마커 존재" 판정(기존 적재분 재조회도 회피), fetch(0행 포함) 후 MarkSwept.
- /// EntityKey 는 문자열 — 복합키는 배치가 구분자로 결합해 전달한다. JobKey 는 job 상수.
- /// </summary>
- public static class SeibroMarkers
- {
- /// <summary>해당 job 의 (EntityKey → LastCheckedAt) 사전 로드 — rolling 대상 정렬 기준.</summary>
- public static async Task<Dictionary<string, DateTime>> LoadFetchMarkersAsync(IAppDbContext db, string jobKey, CancellationToken ct)
- {
- return await db.SeibroFetchMarker.AsNoTracking().Where(c => c.JobKey == jobKey).ToDictionaryAsync(c => c.EntityKey, c => c.LastCheckedAt, ct);
- }
- /// <summary>조회 시도(0행 포함) 후 rolling 마커 upsert — 있으면 Touch, 없으면 Create. 즉시 SaveChanges.</summary>
- public static async Task TouchFetchMarkerAsync(IAppDbContext db, string jobKey, string entityKey, CancellationToken ct)
- {
- var marker = await db.SeibroFetchMarker.FirstOrDefaultAsync(c => c.JobKey == jobKey && c.EntityKey == entityKey, ct);
- if (marker is null)
- {
- await db.SeibroFetchMarker.AddAsync(SeibroFetchMarker.Create(jobKey, entityKey), ct);
- }
- else
- {
- marker.Touch();
- }
- await db.SaveChangesAsync(ct);
- }
- /// <summary>해당 (job, 날짜[, 축])이 이미 조회 완료(0행 포함)로 기록됐는지.</summary>
- public static async Task<bool> IsSweptAsync(IAppDbContext db, string jobKey, DateOnly date, string? discriminator, CancellationToken ct)
- {
- var disc = string.IsNullOrWhiteSpace(discriminator) ? string.Empty : discriminator.Trim();
- return await db.SeibroSweptDate.AsNoTracking().AnyAsync(c => c.JobKey == jobKey && c.Date == date && c.Discriminator == disc, ct);
- }
- /// <summary>조회 완료(0행 포함) 후 날짜 스윕 마커 기록 — 이미 있으면 no-op. 즉시 SaveChanges.</summary>
- public static async Task MarkSweptAsync(IAppDbContext db, string jobKey, DateOnly date, string? discriminator, CancellationToken ct)
- {
- var disc = string.IsNullOrWhiteSpace(discriminator) ? string.Empty : discriminator.Trim();
- if (await db.SeibroSweptDate.AnyAsync(c => c.JobKey == jobKey && c.Date == date && c.Discriminator == disc, ct))
- {
- return;
- }
- await db.SeibroSweptDate.AddAsync(SeibroSweptDate.Create(jobKey, date, disc), ct);
- await db.SaveChangesAsync(ct);
- }
- }
|