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;
}
}