From a4055bee7ee841dc4352186f6f686919c72681d1 Mon Sep 17 00:00:00 2001 From: "HOME-LAPTOP\\kshkulev" Date: Sun, 16 Nov 2025 17:41:58 +0900 Subject: [PATCH] Add operation kind --- .../CampaignManagementService.cs | 4 +- .../DataParsers/DataParserFactory.cs | 5 +- .../BackgroundServices/DataParsingService.cs | 32 +++++++++- .../BackgroundServices/DataParsingState.cs | 58 ++++++++++++++++++- .../BackgroundServices/EventsAggregator.cs | 6 +- .../OperationExecutors/ExecutorFactory.cs | 4 +- .../ResultGetters/ResultGetterFactory.cs | 4 +- Hcs.WebApp/Data/Hcs/Operation.cs | 15 +++++ Hcs.WebApp/Hcs.WebApp.csproj | 5 ++ Hcs.WebApp/Program.cs | 4 ++ 10 files changed, 129 insertions(+), 8 deletions(-) diff --git a/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs b/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs index d33963d..bba33f5 100644 --- a/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs +++ b/Hcs.WebApp/BackgroundServices/CampaignManagementService.cs @@ -8,6 +8,7 @@ namespace Hcs.WebApp.BackgroundServices CampaignManagementState campaignManagementState, OperationExecutionState operationExecutionState, ResultGetState resultGetState, + DataParsingState dataParsingState, ManagerFactory managerFactory, IServiceScopeFactory scopeFactory) : BackgroundService { @@ -18,6 +19,7 @@ namespace Hcs.WebApp.BackgroundServices private readonly CampaignManagementState campaignManagementState = campaignManagementState; private readonly OperationExecutionState operationExecutionState = operationExecutionState; private readonly ResultGetState resultGetState = resultGetState; + private readonly DataParsingState dataParsingState = dataParsingState; private readonly ManagerFactory managerFactory = managerFactory; private readonly IServiceScopeFactory scopeFactory = scopeFactory; private readonly List managers = []; @@ -75,7 +77,7 @@ namespace Hcs.WebApp.BackgroundServices private async Task WaitForOtherStates() { - while (!operationExecutionState.Ready || !resultGetState.Ready) + while (!operationExecutionState.Ready || !resultGetState.Ready || !dataParsingState.Ready) { await Task.Delay(STATES_WAIT_TIME); } diff --git a/Hcs.WebApp/BackgroundServices/DataParsers/DataParserFactory.cs b/Hcs.WebApp/BackgroundServices/DataParsers/DataParserFactory.cs index 5e0c38b..39234ee 100644 --- a/Hcs.WebApp/BackgroundServices/DataParsers/DataParserFactory.cs +++ b/Hcs.WebApp/BackgroundServices/DataParsers/DataParserFactory.cs @@ -9,7 +9,10 @@ namespace Hcs.WebApp.BackgroundServices.DataParsers { return operation.Type switch { - Operation.OperationType.ParseHousesData_15_7_0_1 => new HousesDataParser_15_7_0_1(client, scope, operation) + Operation.OperationType.ParseHousesData_15_7_0_1 => new HousesDataParser_15_7_0_1(client, scope, operation), + + Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1 or + Operation.OperationType.Nsi_ExportNsiItem_15_7_0_1 => throw new ArgumentException($"Нельзя использовать операцию с типом {operation.Type} для парсинга") }; } } diff --git a/Hcs.WebApp/BackgroundServices/DataParsingService.cs b/Hcs.WebApp/BackgroundServices/DataParsingService.cs index 634f1ee..077b9cf 100644 --- a/Hcs.WebApp/BackgroundServices/DataParsingService.cs +++ b/Hcs.WebApp/BackgroundServices/DataParsingService.cs @@ -1,6 +1,34 @@ -namespace Hcs.WebApp.BackgroundServices +using Hcs.WebApp.BackgroundServices.DataParsers; +using Hcs.WebApp.Services; + +namespace Hcs.WebApp.BackgroundServices { - public class DataParsingService + public class DataParsingService( + DataParsingState state, + DataParserFactory dataParserFactory, + IServiceScopeFactory scopeFactory) : BackgroundService { + private readonly DataParsingState state = state; + private readonly DataParserFactory dataParserFactory = dataParserFactory; + private readonly IServiceScopeFactory scopeFactory = scopeFactory; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await InitializeStateAsync(); + } + + private async Task InitializeStateAsync() + { + using var scope = scopeFactory.CreateScope(); + var headquartersService = scope.ServiceProvider.GetRequiredService(); + + var operations = await headquartersService.GetResultWaitingOperationsAsync(); + foreach (var operation in operations) + { + state.EnqueueOperation(operation); + } + + state.Ready = true; + } } } diff --git a/Hcs.WebApp/BackgroundServices/DataParsingState.cs b/Hcs.WebApp/BackgroundServices/DataParsingState.cs index 840ebe7..fc5ea6a 100644 --- a/Hcs.WebApp/BackgroundServices/DataParsingState.cs +++ b/Hcs.WebApp/BackgroundServices/DataParsingState.cs @@ -1,6 +1,62 @@ -namespace Hcs.WebApp.BackgroundServices +using Hcs.WebApp.Data.Hcs; +using System.Collections.Concurrent; + +namespace Hcs.WebApp.BackgroundServices { public class DataParsingState { + private readonly ConcurrentQueue operationsInQueue = new(); + private readonly HashSet operationsInProcess = []; + + public bool Ready { get; set; } + + public event Action OnOperationCreated; + public event OperationStarted OnOperationStarted; + public event OperationEnded OnOperationEnded; + + public void EnqueueOperation(Operation operation) + { + operationsInQueue.Enqueue(operation); + + OnOperationCreated?.Invoke(operation); + } + + public bool TryDequeueOperation(out Operation operation) + { + return operationsInQueue.TryDequeue(out operation); + } + + public void SetProcessingOperation(Operation operation) + { + operationsInProcess.Add(operation); + } + + public void UnsetProcessingOperation(Operation operation) + { + operationsInProcess.Remove(operation); + } + + public bool HasCampaignOperation(int campaignId) + { + return operationsInQueue.Any(x => x.CampaignId == campaignId) || operationsInProcess.Any(x => x.CampaignId == campaignId); + } + + public void InvokeOnOperationStarted(int operationId, int campaignId, DateTime startedAt) + { + try + { + OnOperationStarted?.Invoke(operationId, campaignId, startedAt); + } + catch { } + } + + public void InvokeOnOperationEnded(int operationId, int campaignId, DateTime endedAt, string failureReason) + { + try + { + OnOperationEnded?.Invoke(operationId, campaignId, endedAt, failureReason); + } + catch { } + } } } diff --git a/Hcs.WebApp/BackgroundServices/EventsAggregator.cs b/Hcs.WebApp/BackgroundServices/EventsAggregator.cs index 18d64bf..1840b8d 100644 --- a/Hcs.WebApp/BackgroundServices/EventsAggregator.cs +++ b/Hcs.WebApp/BackgroundServices/EventsAggregator.cs @@ -9,7 +9,7 @@ namespace Hcs.WebApp.BackgroundServices public event OperationExecuted OnOperationExecuted; public event OperationEnded OnOperationEnded; - public EventsAggregator(OperationExecutionState operationExecutionState, ResultGetState resultGetState) + public EventsAggregator(OperationExecutionState operationExecutionState, ResultGetState resultGetState, DataParsingState dataParsingState) { operationExecutionState.OnOperationCreated += (a) => OnOperationCreated?.Invoke(a); operationExecutionState.OnOperationStarted += (a, b, c) => OnOperationStarted?.Invoke(a, b, c); @@ -17,6 +17,10 @@ namespace Hcs.WebApp.BackgroundServices operationExecutionState.OnOperationEnded += (a, b, c, d) => OnOperationEnded?.Invoke(a, b, c, d); resultGetState.OnOperationEnded += (a, b, c, d) => OnOperationEnded?.Invoke(a, b, c, d); + + dataParsingState.OnOperationCreated += (a) => OnOperationCreated?.Invoke(a); + dataParsingState.OnOperationStarted += (a, b, c) => OnOperationStarted?.Invoke(a, b, c); + dataParsingState.OnOperationEnded += (a, b, c, d) => OnOperationEnded?.Invoke(a, b, c, d); } } } diff --git a/Hcs.WebApp/BackgroundServices/OperationExecutors/ExecutorFactory.cs b/Hcs.WebApp/BackgroundServices/OperationExecutors/ExecutorFactory.cs index 0dd18f3..736ca2c 100644 --- a/Hcs.WebApp/BackgroundServices/OperationExecutors/ExecutorFactory.cs +++ b/Hcs.WebApp/BackgroundServices/OperationExecutors/ExecutorFactory.cs @@ -12,7 +12,9 @@ namespace Hcs.WebApp.BackgroundServices.OperationExecutors return operation.Type switch { Operation.OperationType.Nsi_ExportNsiItem_15_7_0_1 => new ExportDataProviderNsiItemExecutor_15_7_0_1(client, scope, operation), - Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1 => new ExportNsiItemExecutor_15_7_0_1(client, scope, operation) + Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1 => new ExportNsiItemExecutor_15_7_0_1(client, scope, operation), + + Operation.OperationType.ParseHousesData_15_7_0_1 => throw new ArgumentException($"Нельзя использовать операцию с типом {operation.Type} для обращения к ГИС ЖКХ") }; } } diff --git a/Hcs.WebApp/BackgroundServices/ResultGetters/ResultGetterFactory.cs b/Hcs.WebApp/BackgroundServices/ResultGetters/ResultGetterFactory.cs index 4450424..15b4513 100644 --- a/Hcs.WebApp/BackgroundServices/ResultGetters/ResultGetterFactory.cs +++ b/Hcs.WebApp/BackgroundServices/ResultGetters/ResultGetterFactory.cs @@ -12,7 +12,9 @@ namespace Hcs.WebApp.BackgroundServices.ResultGetters return operation.Type switch { Operation.OperationType.Nsi_ExportNsiItem_15_7_0_1 => new ExportDataProviderNsiItemGetter_15_7_0_1(client, scope, operation), - Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1 => new ExportNsiItemGetter_15_7_0_1(client, scope, operation) + Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1 => new ExportNsiItemGetter_15_7_0_1(client, scope, operation), + + Operation.OperationType.ParseHousesData_15_7_0_1 => throw new ArgumentException($"Нельзя использовать операцию с типом {operation.Type} для получения результата с ГИС ЖКХ") }; } } diff --git a/Hcs.WebApp/Data/Hcs/Operation.cs b/Hcs.WebApp/Data/Hcs/Operation.cs index a6c1e49..20bc0dd 100644 --- a/Hcs.WebApp/Data/Hcs/Operation.cs +++ b/Hcs.WebApp/Data/Hcs/Operation.cs @@ -17,6 +17,12 @@ namespace Hcs.WebApp.Data.Hcs ParseHousesData_15_7_0_1 } + public enum OperationKind + { + Remote, + Parse + } + public int Id { get; set; } public int CampaignId { get; set; } @@ -41,5 +47,14 @@ namespace Hcs.WebApp.Data.Hcs [NotMapped] public bool Completed => EndedAt.HasValue; + + [NotMapped] + public OperationKind Kind => Type switch + { + OperationType.NsiCommon_ExportNsiItem_15_7_0_1 or + OperationType.Nsi_ExportNsiItem_15_7_0_1 => OperationKind.Remote, + + OperationType.ParseHousesData_15_7_0_1 => OperationKind.Parse + }; } } diff --git a/Hcs.WebApp/Hcs.WebApp.csproj b/Hcs.WebApp/Hcs.WebApp.csproj index 9e73353..1e98475 100644 --- a/Hcs.WebApp/Hcs.WebApp.csproj +++ b/Hcs.WebApp/Hcs.WebApp.csproj @@ -8,6 +8,11 @@ $(DefineConstants);USE_MOCK + $(WarningsAsErrors);NU1605;CS8509 + + + + $(WarningsAsErrors);NU1605;CS8509 diff --git a/Hcs.WebApp/Program.cs b/Hcs.WebApp/Program.cs index ebefe22..7025049 100644 --- a/Hcs.WebApp/Program.cs +++ b/Hcs.WebApp/Program.cs @@ -1,5 +1,6 @@ using Hcs.WebApp.BackgroundServices; using Hcs.WebApp.BackgroundServices.CampaignManagers; +using Hcs.WebApp.BackgroundServices.DataParsers; using Hcs.WebApp.BackgroundServices.OperationExecutors; using Hcs.WebApp.BackgroundServices.ResultGetters; using Hcs.WebApp.Components; @@ -74,16 +75,19 @@ builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); +builder.Services.AddHostedService(); var activator = new RadzenComponentActivator(); activator.Override(typeof(RadzenDataGrid<>), typeof(LocalizedRadzenDataGrid<>));