using Api.SeaHavenIndustries.Observability; using Microsoft.Extensions.Options; using SeaHaven.Services.Configuration; using SeaHaven.Services.Interfaces; using Sentry; namespace Api.SeaHavenIndustries.HostedServices { public class UpliftLifecycleHostedService : BackgroundService { private readonly IServiceScopeFactory _scopeFactory; private readonly ILogger _logger; private readonly ApprovalsOptions _options; private readonly IHub _sentryHub; public UpliftLifecycleHostedService( IServiceScopeFactory scopeFactory, IOptions options, ILogger logger, IHub sentryHub) { _scopeFactory = scopeFactory; _logger = logger; _options = options.Value; _sentryHub = sentryHub; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { { using var transaction = SentryObservability.BeginBackgroundTransaction( _sentryHub, "uplifts.lifecycle-sweep", $"{nameof(UpliftLifecycleHostedService)}.{nameof(SweepAsync)}"); try { await SweepAsync(stoppingToken); transaction.FinishOk(); } catch (OperationCanceledException) { transaction.FinishCancelled(); throw; } catch (Exception ex) { _logger.LogError(ex, "Uplift lifecycle sweep failed; will retry on next interval"); transaction.FinishError(ex); } } await Task.Delay(_options.EffectiveSweepInterval, stoppingToken); } } private async Task SweepAsync(CancellationToken cancellationToken) { using var scope = _scopeFactory.CreateScope(); var lifecycle = scope.ServiceProvider.GetRequiredService(); await lifecycle.ExpireDueAsync(cancellationToken); await lifecycle.SendDueInitialNotificationsAsync(cancellationToken); await lifecycle.EscalateDueAsync(cancellationToken); } } }