108 lines
4.0 KiB
Markdown
108 lines
4.0 KiB
Markdown
# STEP 10 — 정리 서비스 (`ExperionFastCleanupService.cs`) 신규 생성
|
|
|
|
## 사전 확인 (작업 전 반드시 수행)
|
|
|
|
1. `src/Infrastructure/OpcUa/` 디렉토리 목록을 확인한다.
|
|
2. 아래 항목을 확인하고 기록한다:
|
|
- [x] STEP 6이 완료되어 `GetExpiredFastSessionsAsync`, `DeleteFastSessionAsync` 구현이 있는가?
|
|
- [x] `ExperionFastCleanupService.cs` 파일이 이미 존재하는가? → 있으면 내용 비교 후 누락 부분만 수정
|
|
- [x] `IExperionDbService` 인터페이스에 위 두 메서드가 선언되어 있는가?
|
|
|
|
---
|
|
|
|
## 작업 내용
|
|
|
|
**파일**: `src/Infrastructure/OpcUa/ExperionFastCleanupService.cs` (신규 생성)
|
|
|
|
```csharp
|
|
using ExperionCrawler.Core.Application.Interfaces;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace ExperionCrawler.Infrastructure.OpcUa;
|
|
|
|
/// <summary>
|
|
/// fastSession 만료 데이터 정리 서비스.
|
|
/// 매일 03:00 UTC에 실행.
|
|
/// pinned = true 세션은 제외.
|
|
/// retention_days가 null인 세션은 무한 보관.
|
|
/// </summary>
|
|
public class ExperionFastCleanupService : BackgroundService
|
|
{
|
|
private readonly IServiceProvider _sp;
|
|
private readonly ILogger<ExperionFastCleanupService> _logger;
|
|
|
|
public ExperionFastCleanupService(
|
|
IServiceProvider sp,
|
|
ILogger<ExperionFastCleanupService> logger)
|
|
{
|
|
_sp = sp;
|
|
_logger = logger;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
// 매일 03:00 UTC까지 대기
|
|
var now = DateTime.UtcNow;
|
|
var nextRun = new DateTime(now.Year, now.Month, now.Day, 3, 0, 0, DateTimeKind.Utc);
|
|
if (now >= nextRun) nextRun = nextRun.AddDays(1);
|
|
|
|
var delay = nextRun - now;
|
|
_logger.LogInformation("[FastCleanup] 다음 정리 예약: {NextRun} (대기 {Delay})", nextRun, delay);
|
|
|
|
await Task.Delay(delay, stoppingToken);
|
|
|
|
// 만료 세션 조회 및 삭제
|
|
using var scope = _sp.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<IExperionDbService>();
|
|
var expiredList = (await db.GetExpiredFastSessionsAsync()).ToList();
|
|
|
|
foreach (var s in expiredList)
|
|
{
|
|
_logger.LogInformation("[FastCleanup] 세션 {Id} ({Name}) 삭제 — 만료됨", s.Id, s.Name);
|
|
await db.DeleteFastSessionAsync(s.Id);
|
|
}
|
|
|
|
_logger.LogInformation("[FastCleanup] 정리 완료 — {Count}개 세션 삭제", expiredList.Count);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// 정상 종료
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "[FastCleanup] 오류 발생");
|
|
// 오류 시 1시간 후 재시도
|
|
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 사후 확인 (작업 후 반드시 수행)
|
|
|
|
1. `ExperionFastCleanupService.cs` 파일을 열어 전체 내용을 읽는다.
|
|
2. 아래 항목을 하나씩 확인한다:
|
|
- [x] `BackgroundService`를 상속하는가?
|
|
- [x] `ExecuteAsync` 메서드가 있는가?
|
|
- [x] 매일 03:00 UTC 스케줄링 로직이 있는가?
|
|
- [x] `GetExpiredFastSessionsAsync()` 호출이 있는가?
|
|
- [x] 각 만료 세션에 대해 `DeleteFastSessionAsync` 호출이 있는가?
|
|
- [x] `OperationCanceledException` catch가 있는가? (정상 종료 처리)
|
|
- [x] 오류 시 재시도 로직이 있는가?
|
|
3. `dotnet build src/Web/ExperionCrawler.csproj` 실행 → 에러 0, 경고 0개 확인
|
|
4. 문제가 있으면 수정 후 다시 빌드 확인
|
|
|
|
---
|
|
|
|
## 완료 조건
|
|
- `dotnet build src/Web/ExperionCrawler.csproj` 결과: 에러 0, 경고 0
|
|
- `ExperionFastCleanupService.cs` 파일 존재 및 빌드 통과
|
|
- ✅ 완료일: 2026-04-29 |