using MediatR; using Microsoft.Extensions.Options; using Workflow.Application.BuildFlow.Imports.Commands; using Workflow.Application.Reliability; namespace BuildFlow.Host.Services.BackgroundServices; /// /// 周期触发导入任务原子领取命令的 Host 后台服务。 /// public sealed class ImportJobProcessorService( IServiceScopeFactory scopeFactory, IOptionsMonitor options, ILogger logger) : BackgroundService { private readonly string _leaseOwner = $"import:{Environment.MachineName}:{Environment.ProcessId}:{Guid.NewGuid():N}"; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { var importOptions = options.CurrentValue.Import; logger.LogInformation( "ImportJobProcessor 启动,Owner={LeaseOwner},轮询间隔 {Interval}s", _leaseOwner, importOptions.PollIntervalSeconds); try { await Task.Delay( TimeSpan.FromSeconds(importOptions.StartupDelaySeconds), stoppingToken); using var timer = new PeriodicTimer( TimeSpan.FromSeconds(importOptions.PollIntervalSeconds)); do { try { await RunScanAsync(stoppingToken); } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { break; } catch (Exception ex) { logger.LogError(ex, "ImportJobProcessor 单轮处理异常"); } } while (await timer.WaitForNextTickAsync(stoppingToken)); } catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) { // 正常停机。 } logger.LogInformation("ImportJobProcessor 停止,Owner={LeaseOwner}", _leaseOwner); } /// 执行一轮导入任务领取和处理。 public async Task RunScanAsync(CancellationToken ct = default) { using var scope = scopeFactory.CreateScope(); var mediator = scope.ServiceProvider.GetRequiredService(); var importOptions = options.CurrentValue.Import; var processed = await mediator.Send( new ProcessAvailableImportJobsCommand( _leaseOwner, importOptions.BatchSize, TimeSpan.FromSeconds(importOptions.LeaseSeconds), importOptions.MaxAttempts, importOptions.RowsPerBatch), ct); if (processed > 0) { logger.LogInformation( "ImportJobProcessor 完成一轮处理,Owner={LeaseOwner},领取 {Count} 个任务", _leaseOwner, processed); } return processed; } }