using Hcs.Broker; using Hcs.Broker.Logger; using Hcs.Broker.MessageCapturer; using Hcs.WebApp.BackgroundServices.OperationExecutors; using Hcs.WebApp.Config; using Hcs.WebApp.Services; using Hcs.WebApp.Utils; namespace Hcs.WebApp.BackgroundServices { public class OperationExecutionService(OperationExecutionState state, ExecutorFactory executorFactory, IServiceScopeFactory scopeFactory) : BackgroundService { private const int SLEEP_TIME = 30000; private readonly OperationExecutionState state = state; private readonly ExecutorFactory executorFactory = executorFactory; private readonly IServiceScopeFactory scopeFactory = scopeFactory; private Broker.Logger.ILogger logger; private IMessageCapturer messageCapturer; private IClient client; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await InitializeStateAsync(); InitializeClient(); while (!stoppingToken.IsCancellationRequested) { while (state.TryDequeueOperation(out var operation)) { state.SetProcessingOperation(operation); if (stoppingToken.IsCancellationRequested) return; var scope = scopeFactory.CreateScope(); var headquartersService = scope.ServiceProvider.GetRequiredService(); var messageGuid = string.Empty; try { var startedAt = DateTime.UtcNow; await headquartersService.SetOperationStartedAsync(operation.Id, startedAt); state.InvokeOnOperationStarted(operation.Id, operation.CampaignId, startedAt); var executor = executorFactory.CreateExecutor(scope, client, operation); messageGuid = await executor.ExecuteAsync(stoppingToken); } catch (Exception e) { var endedAt = DateTime.UtcNow; var failureReason = e.CombineMessages(); await headquartersService.SetOperationEndedWithFailAsync(operation.Id, endedAt, failureReason); state.InvokeOnOperationEnded(operation.Id, operation.CampaignId, endedAt, failureReason); } if (!string.IsNullOrEmpty(messageGuid)) { await headquartersService.SetOperationMessageGuidAsync(operation.Id, messageGuid); state.InvokeOnOperationExecuted(operation.Id, operation.CampaignId, messageGuid); } state.UnsetProcessingOperation(operation); } await Task.Delay(SLEEP_TIME, stoppingToken); } } private async Task InitializeStateAsync() { using var scope = scopeFactory.CreateScope(); var headquartersService = scope.ServiceProvider.GetRequiredService(); var operations = await headquartersService.GetNotExecutedOperationsAsync(); foreach (var operation in operations) { state.EnqueueOperation(operation); } state.Ready = true; } private void InitializeClient() { logger = new ActionLogger(); messageCapturer = new FileMessageCapturer("outgoing", logger); using var scope = scopeFactory.CreateScope(); var configuration = scope.ServiceProvider.GetRequiredService(); var config = configuration.GetSection("BrokerConfig").Get()!; var clientProvider = scope.ServiceProvider.GetRequiredService(); client = clientProvider.CreateClient(config, logger, messageCapturer); } } }