diff --git a/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs b/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs index 439586d..b56de06 100644 --- a/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs +++ b/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs @@ -40,14 +40,17 @@ namespace Hcs.WebApp.BackgroundServices manager.OnCampaignStarted += OnCampaignStarted; manager.OnCampaignProgressStep += OnCampaignProgressStep; + manager.OnCampaignEnded += OnCampaignEnded; } else { using var scope = scopeFactory.CreateScope(); var headquartersService = scope.ServiceProvider.GetRequiredService(); - await headquartersService.SetCampaignEndedWithFailAsync(campaign.Id, "Не удалось найти подходящий менеджер кампании"); + var endedAt = DateTime.UtcNow; + var failureReason = "Не удалось найти подходящий менеджер кампании"; + await headquartersService.SetCampaignEndedWithFailAsync(campaign.Id, endedAt, failureReason); - campaignManagementState.InvokeOnCampaignEnded(campaign); + campaignManagementState.InvokeOnCampaignEnded(campaign.Id, campaign.Type, endedAt, failureReason); } } @@ -64,10 +67,9 @@ namespace Hcs.WebApp.BackgroundServices if (manager.State == IManager.ManagerState.Ended) { - campaignManagementState.InvokeOnCampaignEnded(manager.Campaign); - manager.OnCampaignStarted -= OnCampaignStarted; manager.OnCampaignProgressStep -= OnCampaignProgressStep; + manager.OnCampaignEnded -= OnCampaignEnded; } } @@ -104,14 +106,19 @@ namespace Hcs.WebApp.BackgroundServices } } - private void OnCampaignStarted(Campaign campaign) + private void OnCampaignStarted(int campaignId, DateTime startedAt) { - campaignManagementState.InvokeOnCampaignStarted(campaign); + campaignManagementState.InvokeOnCampaignStarted(campaignId, startedAt); } - private void OnCampaignProgressStep(Campaign campaign) + private void OnCampaignProgressStep(int campaignId, int step, int progress) { - campaignManagementState.InvokeOnCampaignProgressStep(campaign); + campaignManagementState.InvokeOnCampaignProgressStep(campaignId, step, progress); + } + + private void OnCampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason) + { + campaignManagementState.InvokeOnCampaignEnded(campaignId, type, endedAt, failureReason); } } } diff --git a/Hcs.WebApp/BackgroundServices/CampaignManagementState.cs b/Hcs.WebApp/BackgroundServices/CampaignManagementState.cs index 6792052..8563dce 100644 --- a/Hcs.WebApp/BackgroundServices/CampaignManagementState.cs +++ b/Hcs.WebApp/BackgroundServices/CampaignManagementState.cs @@ -5,12 +5,16 @@ namespace Hcs.WebApp.BackgroundServices { public class CampaignManagementState { + public delegate void CampaignStarted(int campaignId, DateTime startedAt); + public delegate void CampaignProgressStep(int campaignId, int step, int progress); + public delegate void CampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason); + private readonly ConcurrentQueue campaigns = new(); public event Action OnCampaignCreated; - public event Action OnCampaignStarted; - public event Action OnCampaignProgressStep; - public event Action OnCampaignEnded; + public event CampaignStarted OnCampaignStarted; + public event CampaignProgressStep OnCampaignProgressStep; + public event CampaignEnded OnCampaignEnded; public void EnqueueCampaign(Campaign campaign) { @@ -24,29 +28,29 @@ namespace Hcs.WebApp.BackgroundServices return campaigns.TryDequeue(out campaign); } - public void InvokeOnCampaignStarted(Campaign campaign) + public void InvokeOnCampaignStarted(int campaignId, DateTime startedAt) { try { - OnCampaignStarted?.Invoke(campaign); + OnCampaignStarted?.Invoke(campaignId, startedAt); } catch { } } - public void InvokeOnCampaignProgressStep(Campaign campaign) + public void InvokeOnCampaignProgressStep(int campaignId, int step, int progress) { try { - OnCampaignProgressStep?.Invoke(campaign); + OnCampaignProgressStep?.Invoke(campaignId, step, progress); } catch { } } - public void InvokeOnCampaignEnded(Campaign campaign) + public void InvokeOnCampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason) { try { - OnCampaignEnded?.Invoke(campaign); + OnCampaignEnded?.Invoke(campaignId, type, endedAt, failureReason); } catch { } } diff --git a/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportCommonRegistryElementsManager_15_7_0_1.cs b/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportCommonRegistryElementsManager_15_7_0_1.cs index 8977271..77c277d 100644 --- a/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportCommonRegistryElementsManager_15_7_0_1.cs +++ b/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportCommonRegistryElementsManager_15_7_0_1.cs @@ -44,6 +44,7 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers private async Task DoStartStepAsync() { + DateTime startedAt = default; IEnumerable? operations = null; using var context = HeadquartersService.GetNewContext(); @@ -53,7 +54,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers using var transaction = await context.Database.BeginTransactionAsync(); try { - await HeadquartersService.SetCampaignStartedAsync(context, campaign.Id); + startedAt = DateTime.UtcNow; + await HeadquartersService.SetCampaignStartedAsync(context, campaign.Id, startedAt); await ProgressStepAsync(context, (int)Step.ExecutionWait); @@ -80,6 +82,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers } State = IManager.ManagerState.Started; + + InvokeOnCampaignStarted(startedAt); } private async Task DoExecutionWaitStepAsync() @@ -102,6 +106,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers { if (resultWaitState.HasCampaignOperation(campaign.Id)) return; + DateTime endedAt = default; + using var context = HeadquartersService.GetNewContext(); var executionStrategy = context.Database.CreateExecutionStrategy(); await executionStrategy.ExecuteAsync(async () => @@ -111,7 +117,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers { await ProgressStepAsync(context, (int)Step.End); - await HeadquartersService.SetCampaignEndedAsync(context, campaign.Id); + endedAt = DateTime.UtcNow; + await HeadquartersService.SetCampaignEndedAsync(context, campaign.Id, endedAt); await transaction.CommitAsync(); } @@ -124,6 +131,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers }); State = IManager.ManagerState.Ended; + + InvokeOnCampaignEnded(endedAt, string.Empty); } } } diff --git a/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportPrivateRegistryElementsManager_15_7_0_1.cs b/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportPrivateRegistryElementsManager_15_7_0_1.cs index 5fab90d..b8bb081 100644 --- a/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportPrivateRegistryElementsManager_15_7_0_1.cs +++ b/Hcs.WebApp/BackgroundServices/CampaignManagers/ExportPrivateRegistryElementsManager_15_7_0_1.cs @@ -44,6 +44,7 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers private async Task DoStartStepAsync() { + DateTime startedAt = default; IEnumerable? operations = null; using var context = HeadquartersService.GetNewContext(); @@ -53,7 +54,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers using var transaction = await context.Database.BeginTransactionAsync(); try { - await HeadquartersService.SetCampaignStartedAsync(context, campaign.Id); + startedAt = DateTime.UtcNow; + await HeadquartersService.SetCampaignStartedAsync(context, campaign.Id, startedAt); await ProgressStepAsync(context, (int)Step.ExecutionWait); @@ -80,6 +82,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers } State = IManager.ManagerState.Started; + + InvokeOnCampaignStarted(startedAt); } private async Task DoExecutionWaitStepAsync() @@ -102,6 +106,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers { if (resultWaitState.HasCampaignOperation(campaign.Id)) return; + DateTime endedAt = default; + using var context = HeadquartersService.GetNewContext(); var executionStrategy = context.Database.CreateExecutionStrategy(); await executionStrategy.ExecuteAsync(async () => @@ -111,7 +117,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers { await ProgressStepAsync(context, (int)Step.End); - await HeadquartersService.SetCampaignEndedAsync(context, campaign.Id); + endedAt = DateTime.UtcNow; + await HeadquartersService.SetCampaignEndedAsync(context, campaign.Id, endedAt); await transaction.CommitAsync(); } @@ -124,6 +131,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers }); State = IManager.ManagerState.Ended; + + InvokeOnCampaignEnded(endedAt, string.Empty); } } } diff --git a/Hcs.WebApp/BackgroundServices/CampaignManagers/IManager.cs b/Hcs.WebApp/BackgroundServices/CampaignManagers/IManager.cs index 79d1a64..5af0f51 100644 --- a/Hcs.WebApp/BackgroundServices/CampaignManagers/IManager.cs +++ b/Hcs.WebApp/BackgroundServices/CampaignManagers/IManager.cs @@ -4,6 +4,10 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers { public interface IManager { + public delegate void CampaignStarted(int campaignId, DateTime startedAt); + public delegate void CampaignProgressStep(int campaignId, int step, int progress); + public delegate void CampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason); + public enum ManagerState { Created, @@ -15,8 +19,9 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers public ManagerState State { get; } - event Action OnCampaignStarted; - event Action OnCampaignProgressStep; + event CampaignStarted OnCampaignStarted; + event CampaignProgressStep OnCampaignProgressStep; + event CampaignEnded OnCampaignEnded; Task ProcessAsync(); diff --git a/Hcs.WebApp/BackgroundServices/CampaignManagers/ManagerBase.cs b/Hcs.WebApp/BackgroundServices/CampaignManagers/ManagerBase.cs index f599395..359a44e 100644 --- a/Hcs.WebApp/BackgroundServices/CampaignManagers/ManagerBase.cs +++ b/Hcs.WebApp/BackgroundServices/CampaignManagers/ManagerBase.cs @@ -15,42 +15,36 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers protected readonly ResultWaitState resultWaitState = resultWaitState; protected readonly Campaign campaign = campaign; - private IManager.ManagerState state; private HeadquartersService? headquartersService; public Campaign Campaign => campaign; - public IManager.ManagerState State - { - get => state; - set - { - if (state != value) - { - state = value; - - if (state == IManager.ManagerState.Started) - { - OnCampaignStarted?.Invoke(campaign); - } - } - } - } + public IManager.ManagerState State { get; protected set; } protected HeadquartersService HeadquartersService => headquartersService ??= scope.ServiceProvider.GetRequiredService(); protected abstract int StepCount { get; } - public event Action OnCampaignStarted; - public event Action? OnCampaignProgressStep; + public event IManager.CampaignStarted OnCampaignStarted; + public event IManager.CampaignProgressStep OnCampaignProgressStep; + public event IManager.CampaignEnded OnCampaignEnded; public abstract Task ProcessAsync(); public async Task EndWithFailAsync(Exception e) { - await HeadquartersService.SetCampaignEndedWithFailAsync(campaign.Id, e.CombineMessages()); + var endedAt = DateTime.UtcNow; + var failureReason = e.CombineMessages(); + await HeadquartersService.SetCampaignEndedWithFailAsync(campaign.Id, endedAt, failureReason); State = IManager.ManagerState.Ended; + + InvokeOnCampaignEnded(endedAt, failureReason); + } + + protected void InvokeOnCampaignStarted(DateTime startedAt) + { + OnCampaignStarted?.Invoke(campaign.Id, startedAt); } protected async Task ProgressStepAsync(int step) @@ -59,13 +53,18 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers await ProgressStepAsync(context, step); } + protected void InvokeOnCampaignEnded(DateTime endedAt, string failureReason) + { + OnCampaignEnded?.Invoke(campaign.Id, campaign.Type, endedAt, failureReason); + } + protected async Task ProgressStepAsync(HcsDbContext context, int step) { campaign.Step = step; campaign.Progress = Convert.ToInt32(((step + 1) / (float)StepCount * 100)); await HeadquartersService.UpdateCampaignStepAndProgressAsync(context, campaign); - OnCampaignProgressStep?.Invoke(campaign); + OnCampaignProgressStep?.Invoke(campaign.Id, campaign.Step, campaign.Progress); } } } diff --git a/Hcs.WebApp/Components/Pages/Campaigns.razor b/Hcs.WebApp/Components/Pages/Campaigns.razor index b7a924d..89d25c9 100644 --- a/Hcs.WebApp/Components/Pages/Campaigns.razor +++ b/Hcs.WebApp/Components/Pages/Campaigns.razor @@ -137,38 +137,38 @@ Task.Run(RefreshCampaigns); } - void OnCampaignStarted(Campaign campaign) + void OnCampaignStarted(int campaignId, DateTime startedAt) { InvokeAsync(() => { - var targetCampaign = campaigns?.FirstOrDefault(x => x.Id == campaign.Id); + var targetCampaign = campaigns?.FirstOrDefault(x => x.Id == campaignId); if (targetCampaign != null) { - targetCampaign.StartedAt = campaign.StartedAt; + targetCampaign.StartedAt = startedAt; campaignsDataGrid.Reload(); } - if (expandedCampaign != null && expandedCampaign.Id == campaign.Id) + if (expandedCampaign != null && expandedCampaign.Id == campaignId) { campaignsDataGrid.CollapseAll(); } }); } - void OnCampaignProgressStep(Campaign campaign) + void OnCampaignProgressStep(int campaignId, int step, int progress) { InvokeAsync(() => { - var targetCampaign = campaigns?.FirstOrDefault(x => x.Id == campaign.Id); + var targetCampaign = campaigns?.FirstOrDefault(x => x.Id == campaignId); if (targetCampaign != null) { - targetCampaign.Step = campaign.Step; - targetCampaign.Progress = campaign.Progress; + targetCampaign.Step = step; + targetCampaign.Progress = progress; campaignsDataGrid.Reload(); - if (expandedCampaign != null && expandedCampaign.Id == campaign.Id) + if (expandedCampaign != null && expandedCampaign.Id == campaignId) { campaignsDataGrid.CollapseAll(); } @@ -176,7 +176,7 @@ }); } - void OnCampaignEnded(Campaign campaign) + void OnCampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason) { Task.Run(RefreshCampaigns); } diff --git a/Hcs.WebApp/Components/Pages/Registry/Common.razor b/Hcs.WebApp/Components/Pages/Registry/Common.razor index 7ebfb27..b7ae566 100644 --- a/Hcs.WebApp/Components/Pages/Registry/Common.razor +++ b/Hcs.WebApp/Components/Pages/Registry/Common.razor @@ -184,9 +184,9 @@ } } - void OnCampaignEnded(Campaign campaign) + void OnCampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason) { - if (campaign.Type == Campaign.CampaignType.ExportCommonRegistryElements_15_7_0_1) + if (type == Campaign.CampaignType.ExportCommonRegistryElements_15_7_0_1) { Task.Run(RefreshRegistries); } diff --git a/Hcs.WebApp/Components/Pages/Registry/Private.razor b/Hcs.WebApp/Components/Pages/Registry/Private.razor index d5d0164..4053686 100644 --- a/Hcs.WebApp/Components/Pages/Registry/Private.razor +++ b/Hcs.WebApp/Components/Pages/Registry/Private.razor @@ -184,9 +184,9 @@ } } - void OnCampaignEnded(Campaign campaign) + void OnCampaignEnded(int campaignId, Campaign.CampaignType type, DateTime endedAt, string failureReason) { - if (campaign.Type == Campaign.CampaignType.ExportPrivateRegistryElements_15_7_0_1) + if (type == Campaign.CampaignType.ExportPrivateRegistryElements_15_7_0_1) { Task.Run(RefreshRegistries); } diff --git a/Hcs.WebApp/Services/HeadquartersService.cs b/Hcs.WebApp/Services/HeadquartersService.cs index 759f11c..f2fd474 100644 --- a/Hcs.WebApp/Services/HeadquartersService.cs +++ b/Hcs.WebApp/Services/HeadquartersService.cs @@ -80,12 +80,12 @@ namespace Hcs.WebApp.Services return operations; } - public async Task SetCampaignStartedAsync(HcsDbContext context, int campaignId) + public async Task SetCampaignStartedAsync(HcsDbContext context, int campaignId, DateTime startedAt) { var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId); if (campaign != null) { - campaign.StartedAt = DateTime.UtcNow; + campaign.StartedAt = startedAt; await context.SaveChangesAsync(); } @@ -103,30 +103,30 @@ namespace Hcs.WebApp.Services } } - public async Task SetCampaignEndedAsync(int campaignId) + public async Task SetCampaignEndedAsync(int campaignId, DateTime endedAt) { using var context = GetNewContext(); - await SetCampaignEndedAsync(context, campaignId); + await SetCampaignEndedAsync(context, campaignId, endedAt); } - public async Task SetCampaignEndedAsync(HcsDbContext context, int campaignId) + public async Task SetCampaignEndedAsync(HcsDbContext context, int campaignId, DateTime endedAt) { var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId); if (campaign != null) { - campaign.EndedAt = DateTime.UtcNow; + campaign.EndedAt = endedAt; await context.SaveChangesAsync(); } } - public async Task SetCampaignEndedWithFailAsync(int campaignId, string failureReason) + public async Task SetCampaignEndedWithFailAsync(int campaignId, DateTime endedAt, string failureReason) { using var context = GetNewContext(); var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId); if (campaign != null) { - campaign.EndedAt = DateTime.UtcNow; + campaign.EndedAt = endedAt; campaign.FailureReason = failureReason; await context.SaveChangesAsync();