| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- using Furion.Schedule;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using System.Text.Json;
- using Admin.NET.Plugin.AiDOP.DataPlatform.MdpRebuild;
- namespace Admin.NET.Plugin.AiDOP.Job;
- /// <summary>
- /// S1–S7 夜间串行全量兜底。triggerType 用 <see cref="ModuleRebuildTriggerType.AutoNightly"/>,
- /// 穿透 AUTO 冷却窗口;串行靠 <c>GlobalMaxParallelScopes = 1</c>,本 Job 一次性入队全部 scope。
- ///
- /// <para><b>扇出前先清自己上一轮未开跑的入队</b>:日度全量重算的排队记录过了当天就没有价值,
- /// 今天这一轮天然取代昨天那一轮。不清的后果实测过——2026-09-28 有 28 条 03:40 入队的
- /// <c>AUTO_NIGHTLY</c> 因执行机指派丢失而无人可领,一直挡着同 scope 的后续入队。
- /// 只清 <c>QUEUED</c> 且无 <c>requested_by</c> 的行,RUNNING 与页面手工任务一律不碰。</para>
- [JobDetail("job_mdp_nightly_full_rebuild",
- Description = "S1–S7 夜间串行全量兜底(穿透 AUTO 冷却窗口)",
- GroupName = "default",
- Concurrent = false)]
- [Cron("40 3 * * *",
- TriggerId = "trigger_mdp_nightly_full_rebuild",
- Description = "每日 03:40 触发(5 字段:分 时 日 月 周)")]
- public class MdpNightlyFullRebuildJob : IJob
- {
- private static readonly string[] Modules = ["S1", "S2", "S3", "S4", "S5", "S6", "S7"];
- private readonly IServiceScopeFactory _scopeFactory;
- private readonly ILogger _logger;
- public MdpNightlyFullRebuildJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
- {
- _scopeFactory = scopeFactory;
- _logger = loggerFactory.CreateLogger(nameof(MdpNightlyFullRebuildJob));
- }
- public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
- {
- if (!AidopJobGate.ShouldRun(nameof(MdpNightlyFullRebuildJob), _logger)) return;
- using var scope = _scopeFactory.CreateScope();
- try
- {
- var stale = await scope.ServiceProvider.GetRequiredService<IModuleRebuildJobStore>()
- .CancelUnstartedByTriggerAsync(
- ModuleRebuildTriggerType.AutoNightly,
- TimeSpan.Zero,
- "已被今日夜间全量取代(上一轮未开跑)",
- stoppingToken);
- if (stale > 0)
- _logger.LogWarning(
- "MdpNightlyFullRebuildJob 清理上一轮未开跑的 AUTO_NIGHTLY {Count} 条。"
- + "条数偏高说明队列此前长期无人消费,请查 MDP 运行监控页的执行机指派",
- stale);
- foreach (var module in Modules)
- {
- stoppingToken.ThrowIfCancellationRequested();
- var payload = await ModuleRebuildJobRunner.EnqueueEnabledScopesAsync(
- scope.ServiceProvider, module, ModuleRebuildTriggerType.AutoNightly, stoppingToken, _logger);
- _logger.LogInformation("MdpNightlyFullRebuildJob {Module} 入队 {Payload}", module, JsonSerializer.Serialize(payload));
- }
- }
- catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
- {
- _logger.LogInformation("MdpNightlyFullRebuildJob 收到停止信号,本轮结束");
- throw;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "MdpNightlyFullRebuildJob 入队失败");
- }
- }
- }
|