using Hcs.WebApp.BackgroundServices.CampaignManagers; using Hcs.WebApp.Data.Hcs; using Hcs.WebApp.Services; namespace Hcs.WebApp.BackgroundServices { public class CampaignManagementService( CampaignManagementState campaignManagementState, OperationExecutionState operationExecutionState, ResultWaitState resultWaitState, ManagerFactory managerFactory, IServiceScopeFactory scopeFactory) : BackgroundService { private const int STATES_WAIT_TIME = 1000; private const int ITERATION_TIME = 1000; private const int SLEEP_TIME = 30000; private readonly CampaignManagementState campaignManagementState = campaignManagementState; private readonly OperationExecutionState operationExecutionState = operationExecutionState; private readonly ResultWaitState resultWaitState = resultWaitState; private readonly ManagerFactory managerFactory = managerFactory; private readonly IServiceScopeFactory scopeFactory = scopeFactory; private readonly List managers = []; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await WaitForOtherStates(); await InitializeStateAsync(); while (!stoppingToken.IsCancellationRequested) { while (campaignManagementState.TryDequeueCampaign(out var campaign)) { if (stoppingToken.IsCancellationRequested) return; var manager = managerFactory.CreateManager(campaign); if (manager != null) { managers.Add(manager); manager.OnCampaignStarted += OnCampaignStarted; manager.OnCampaignProgressStep += OnCampaignProgressStep; manager.OnCampaignEnded += OnCampaignEnded; } else { using var scope = scopeFactory.CreateScope(); var headquartersService = scope.ServiceProvider.GetRequiredService(); var endedAt = DateTime.UtcNow; var failureReason = "Не удалось найти подходящий менеджер кампании"; await headquartersService.SetCampaignEndedWithFailAsync(campaign.Id, endedAt, failureReason); campaignManagementState.InvokeOnCampaignEnded(campaign.Id, campaign.Type, endedAt, failureReason); } } foreach (var manager in managers) { try { await manager.ProcessAsync(); } catch (Exception e) { await manager.EndWithFailAsync(e); } if (manager.State == IManager.ManagerState.Ended) { manager.OnCampaignStarted -= OnCampaignStarted; manager.OnCampaignProgressStep -= OnCampaignProgressStep; manager.OnCampaignEnded -= OnCampaignEnded; } } managers.RemoveAll(x => x.State == IManager.ManagerState.Ended); if (managers.Count > 0) { await Task.Delay(ITERATION_TIME, stoppingToken); } else { await Task.Delay(SLEEP_TIME, stoppingToken); } } } private async Task WaitForOtherStates() { while (!operationExecutionState.Ready || !resultWaitState.Ready) { await Task.Delay(STATES_WAIT_TIME); } } private async Task InitializeStateAsync() { using var scope = scopeFactory.CreateScope(); var headquartersService = scope.ServiceProvider.GetRequiredService(); var campaigns = await headquartersService.GetNotEndedCampaignsAsync(); foreach (var campaign in campaigns) { campaignManagementState.EnqueueCampaign(campaign); } } private void OnCampaignStarted(int campaignId, DateTime startedAt) { campaignManagementState.InvokeOnCampaignStarted(campaignId, startedAt); } private void OnCampaignProgressStep(int campaignId, int step, int progress) { campaignManagementState.InvokeOnCampaignProgressStep(campaignId, step, progress); } private void OnCampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason) { campaignManagementState.InvokeOnCampaignEnded(campaignId, type, endedAt, failureReason); } } }