using Admin.NET.Plugin.AiDOP.Infrastructure; using Admin.NET.Plugin.AiDOP.SmartOps; using Furion.Schedule; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using SqlSugar; namespace Admin.NET.Plugin.AiDOP.Job; /// /// 原子聚合表为空时(含 schema 修复后)自动构建四域全量历史原子 KPI,无需等待 hourly MDP。 /// [JobDetail("job_smart_ops_kpi_atomic_warmup", Description = "智慧运营KPI:原子层为空时自动预热(四域全量历史)", GroupName = "default", Concurrent = false)] [PeriodSeconds(2, TriggerId = "trigger_smart_ops_kpi_atomic_warmup", Description = "启动后检测原子层并预热", MaxNumberOfRuns = 1, RunOnStart = true)] public class SmartOpsKpiAtomicWarmupJob : IJob { private readonly IServiceScopeFactory _scopeFactory; private readonly ILogger _logger; public SmartOpsKpiAtomicWarmupJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory) { _scopeFactory = scopeFactory; _logger = loggerFactory.CreateLogger(nameof(SmartOpsKpiAtomicWarmupJob)); } public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken) { using var scope = _scopeFactory.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); var build = scope.ServiceProvider.GetRequiredService(); try { AidopTenantMigration.EnsureKpiAtomicTable(db); var rowCount = await db.Ado.GetIntAsync( "SELECT COUNT(1) FROM ado_smart_ops_kpi_atomic_day WHERE is_deleted = 0"); if (rowCount > 0) { _logger.LogInformation("SmartOpsKpiAtomicWarmupJob: 原子层已有 {RowCount} 行,跳过预热", rowCount); return; } const string batchId = "ATOMIC_WARMUP"; var orderRows = await build.BuildOrderDeliveryDomainForAllDatesAsync(batchId, cancellationToken: stoppingToken); var scheduleRows = await build.BuildWorkScheduleDomainForAllDatesAsync(batchId, cancellationToken: stoppingToken); var supplyRows = await build.BuildSupplyPurchaseDomainForAllDatesAsync(batchId, cancellationToken: stoppingToken); var inventoryRows = await build.BuildInventoryDomainForAllDatesAsync(batchId, cancellationToken: stoppingToken); _logger.LogInformation( "SmartOpsKpiAtomicWarmupJob: 预热完成 order={OrderRows} schedule={ScheduleRows} supply={SupplyRows} inventory={InventoryRows}", orderRows, scheduleRows, supplyRows, inventoryRows); } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { _logger.LogInformation("SmartOpsKpiAtomicWarmupJob: 收到停止信号"); throw; } catch (Exception ex) { _logger.LogError(ex, "SmartOpsKpiAtomicWarmupJob: 原子层预热失败"); } } }