Add operation kind

This commit is contained in:
2025-11-16 17:41:58 +09:00
parent 6abff9cc7e
commit a4055bee7e
10 changed files with 129 additions and 8 deletions

View File

@ -8,6 +8,7 @@ namespace Hcs.WebApp.BackgroundServices
CampaignManagementState campaignManagementState, CampaignManagementState campaignManagementState,
OperationExecutionState operationExecutionState, OperationExecutionState operationExecutionState,
ResultGetState resultGetState, ResultGetState resultGetState,
DataParsingState dataParsingState,
ManagerFactory managerFactory, ManagerFactory managerFactory,
IServiceScopeFactory scopeFactory) : BackgroundService IServiceScopeFactory scopeFactory) : BackgroundService
{ {
@ -18,6 +19,7 @@ namespace Hcs.WebApp.BackgroundServices
private readonly CampaignManagementState campaignManagementState = campaignManagementState; private readonly CampaignManagementState campaignManagementState = campaignManagementState;
private readonly OperationExecutionState operationExecutionState = operationExecutionState; private readonly OperationExecutionState operationExecutionState = operationExecutionState;
private readonly ResultGetState resultGetState = resultGetState; private readonly ResultGetState resultGetState = resultGetState;
private readonly DataParsingState dataParsingState = dataParsingState;
private readonly ManagerFactory managerFactory = managerFactory; private readonly ManagerFactory managerFactory = managerFactory;
private readonly IServiceScopeFactory scopeFactory = scopeFactory; private readonly IServiceScopeFactory scopeFactory = scopeFactory;
private readonly List<IManager> managers = []; private readonly List<IManager> managers = [];
@ -75,7 +77,7 @@ namespace Hcs.WebApp.BackgroundServices
private async Task WaitForOtherStates() private async Task WaitForOtherStates()
{ {
while (!operationExecutionState.Ready || !resultGetState.Ready) while (!operationExecutionState.Ready || !resultGetState.Ready || !dataParsingState.Ready)
{ {
await Task.Delay(STATES_WAIT_TIME); await Task.Delay(STATES_WAIT_TIME);
} }

View File

@ -9,7 +9,10 @@ namespace Hcs.WebApp.BackgroundServices.DataParsers
{ {
return operation.Type switch 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} для парсинга")
}; };
} }
} }

View File

@ -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<HeadquartersService>();
var operations = await headquartersService.GetResultWaitingOperationsAsync();
foreach (var operation in operations)
{
state.EnqueueOperation(operation);
}
state.Ready = true;
}
} }
} }

View File

@ -1,6 +1,62 @@
namespace Hcs.WebApp.BackgroundServices using Hcs.WebApp.Data.Hcs;
using System.Collections.Concurrent;
namespace Hcs.WebApp.BackgroundServices
{ {
public class DataParsingState public class DataParsingState
{ {
private readonly ConcurrentQueue<Operation> operationsInQueue = new();
private readonly HashSet<Operation> operationsInProcess = [];
public bool Ready { get; set; }
public event Action<Operation> 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 { }
}
} }
} }

View File

@ -9,7 +9,7 @@ namespace Hcs.WebApp.BackgroundServices
public event OperationExecuted OnOperationExecuted; public event OperationExecuted OnOperationExecuted;
public event OperationEnded OnOperationEnded; 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.OnOperationCreated += (a) => OnOperationCreated?.Invoke(a);
operationExecutionState.OnOperationStarted += (a, b, c) => OnOperationStarted?.Invoke(a, b, c); 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); operationExecutionState.OnOperationEnded += (a, b, c, d) => OnOperationEnded?.Invoke(a, b, c, d);
resultGetState.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);
} }
} }
} }

View File

@ -12,7 +12,9 @@ namespace Hcs.WebApp.BackgroundServices.OperationExecutors
return operation.Type switch return operation.Type switch
{ {
Operation.OperationType.Nsi_ExportNsiItem_15_7_0_1 => new ExportDataProviderNsiItemExecutor_15_7_0_1(client, scope, operation), 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} для обращения к ГИС ЖКХ")
}; };
} }
} }

View File

@ -12,7 +12,9 @@ namespace Hcs.WebApp.BackgroundServices.ResultGetters
return operation.Type switch return operation.Type switch
{ {
Operation.OperationType.Nsi_ExportNsiItem_15_7_0_1 => new ExportDataProviderNsiItemGetter_15_7_0_1(client, scope, operation), 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} для получения результата с ГИС ЖКХ")
}; };
} }
} }

View File

@ -17,6 +17,12 @@ namespace Hcs.WebApp.Data.Hcs
ParseHousesData_15_7_0_1 ParseHousesData_15_7_0_1
} }
public enum OperationKind
{
Remote,
Parse
}
public int Id { get; set; } public int Id { get; set; }
public int CampaignId { get; set; } public int CampaignId { get; set; }
@ -41,5 +47,14 @@ namespace Hcs.WebApp.Data.Hcs
[NotMapped] [NotMapped]
public bool Completed => EndedAt.HasValue; 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
};
} }
} }

View File

@ -8,6 +8,11 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>$(DefineConstants);USE_MOCK</DefineConstants> <DefineConstants>$(DefineConstants);USE_MOCK</DefineConstants>
<WarningsAsErrors>$(WarningsAsErrors);NU1605;CS8509</WarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<WarningsAsErrors>$(WarningsAsErrors);NU1605;CS8509</WarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,5 +1,6 @@
using Hcs.WebApp.BackgroundServices; using Hcs.WebApp.BackgroundServices;
using Hcs.WebApp.BackgroundServices.CampaignManagers; using Hcs.WebApp.BackgroundServices.CampaignManagers;
using Hcs.WebApp.BackgroundServices.DataParsers;
using Hcs.WebApp.BackgroundServices.OperationExecutors; using Hcs.WebApp.BackgroundServices.OperationExecutors;
using Hcs.WebApp.BackgroundServices.ResultGetters; using Hcs.WebApp.BackgroundServices.ResultGetters;
using Hcs.WebApp.Components; using Hcs.WebApp.Components;
@ -74,16 +75,19 @@ builder.Services.AddScoped<HouseService>();
builder.Services.AddSingleton<CampaignManagementState>(); builder.Services.AddSingleton<CampaignManagementState>();
builder.Services.AddSingleton<OperationExecutionState>(); builder.Services.AddSingleton<OperationExecutionState>();
builder.Services.AddSingleton<ResultGetState>(); builder.Services.AddSingleton<ResultGetState>();
builder.Services.AddSingleton<DataParsingState>();
builder.Services.AddSingleton<ManagerFactory>(); builder.Services.AddSingleton<ManagerFactory>();
builder.Services.AddSingleton<ExecutorFactory>(); builder.Services.AddSingleton<ExecutorFactory>();
builder.Services.AddSingleton<ResultGetterFactory>(); builder.Services.AddSingleton<ResultGetterFactory>();
builder.Services.AddSingleton<DataParserFactory>();
builder.Services.AddSingleton<EventsAggregator>(); builder.Services.AddSingleton<EventsAggregator>();
builder.Services.AddHostedService<CampaignManagementService>(); builder.Services.AddHostedService<CampaignManagementService>();
builder.Services.AddHostedService<OperationExecutionService>(); builder.Services.AddHostedService<OperationExecutionService>();
builder.Services.AddHostedService<ResultGetService>(); builder.Services.AddHostedService<ResultGetService>();
builder.Services.AddHostedService<DataParsingService>();
var activator = new RadzenComponentActivator(); var activator = new RadzenComponentActivator();
activator.Override(typeof(RadzenDataGrid<>), typeof(LocalizedRadzenDataGrid<>)); activator.Override(typeof(RadzenDataGrid<>), typeof(LocalizedRadzenDataGrid<>));