shoc-backend/Api.SeaHavenIndustries/HostedServices/WorkOrderReconciliationHostedService.cs

86 lines
3.3 KiB
C#
Raw Normal View History

using Microsoft.Extensions.Options;
using SeaHaven.Services.Configuration;
using SeaHaven.Services.Interfaces;
namespace Api.SeaHavenIndustries.HostedServices
{
public sealed class WorkOrderReconciliationHostedService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly IOptionsMonitor<WorkOrderReconciliationOptions> _options;
private readonly TimeProvider _timeProvider;
private readonly ILogger<WorkOrderReconciliationHostedService> _logger;
public WorkOrderReconciliationHostedService(
IServiceScopeFactory scopeFactory,
IOptionsMonitor<WorkOrderReconciliationOptions> options,
TimeProvider timeProvider,
ILogger<WorkOrderReconciliationHostedService> logger)
{
_scopeFactory = scopeFactory;
_options = options;
_timeProvider = timeProvider;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var nextScheduledAt = _timeProvider.GetUtcNow();
if (_options.CurrentValue.Enabled && _options.CurrentValue.RunOnStartup)
{
await TriggerAsync("startup", stoppingToken);
nextScheduledAt = _timeProvider.GetUtcNow().AddMinutes(_options.CurrentValue.ScheduleMinutes);
}
while (!stoppingToken.IsCancellationRequested)
{
var options = _options.CurrentValue;
if (options.Enabled)
{
var now = _timeProvider.GetUtcNow();
if (now >= nextScheduledAt)
{
await TriggerAsync("schedule", stoppingToken);
nextScheduledAt = now.AddMinutes(options.ScheduleMinutes);
}
await RunPendingAsync(stoppingToken);
}
await Task.Delay(
TimeSpan.FromSeconds(Math.Clamp(options.PollSeconds, 1, 300)),
_timeProvider,
stoppingToken);
}
}
private async Task TriggerAsync(string reason, CancellationToken cancellationToken)
{
try
{
await using var scope = _scopeFactory.CreateAsyncScope();
var runner = scope.ServiceProvider.GetRequiredService<IWorkOrderReconciliationRunner>();
await runner.TriggerAsync(reason, cancellationToken);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
_logger.LogError(ex, "Could not queue procurement reconciliation.");
}
}
private async Task RunPendingAsync(CancellationToken cancellationToken)
{
try
{
await using var scope = _scopeFactory.CreateAsyncScope();
var runner = scope.ServiceProvider.GetRequiredService<IWorkOrderReconciliationRunner>();
await runner.RunPendingAsync(cancellationToken);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
_logger.LogError(ex, "Could not execute procurement reconciliation.");
}
}
}
}