2026-07-24 09:10:49 +08:00

86 lines
2.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using MediatR;
using Microsoft.Extensions.Options;
using Workflow.Application.BuildFlow.Imports.Commands;
using Workflow.Application.Reliability;
namespace BuildFlow.Host.Services.BackgroundServices;
/// <summary>
/// 周期触发导入任务原子领取命令的 Host 后台服务。
/// </summary>
public sealed class ImportJobProcessorService(
IServiceScopeFactory scopeFactory,
IOptionsMonitor<WorkflowJobOptions> options,
ILogger<ImportJobProcessorService> 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);
}
/// <summary>执行一轮导入任务领取和处理。</summary>
public async Task<int> RunScanAsync(CancellationToken ct = default)
{
using var scope = scopeFactory.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
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;
}
}