Add campaign manager

This commit is contained in:
2025-10-27 10:02:58 +09:00
parent 891d462af1
commit 7c35c9a7df
18 changed files with 250 additions and 41 deletions

View File

@ -0,0 +1,55 @@
using Hcs.WebApp.BackgroundServices.CampaignManagers;
using Hcs.WebApp.Services;
namespace Hcs.WebApp.BackgroundServices
{
public class CampaignManagementService(
CampaignManagementState campaignManagementState,
ManagerFactory managerFactory,
IServiceScopeFactory scopeFactory) : BackgroundService
{
private const int SLEEP_TIME = 30000;
private readonly CampaignManagementState campaignManagementState = campaignManagementState;
private readonly ManagerFactory managerFactory = managerFactory;
private readonly IServiceScopeFactory scopeFactory = scopeFactory;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await InitializeStateAsync();
while (!stoppingToken.IsCancellationRequested)
{
while (campaignManagementState.TryDequeueCampaign(out var campaign))
{
if (stoppingToken.IsCancellationRequested) return;
try
{
var manager = managerFactory.CreateManager(campaign);
await manager.StartAsync(stoppingToken);
}
catch
{
// TODO: Добавить таймауты
campaignManagementState.EnqueueCampaign(campaign);
}
}
await Task.Delay(SLEEP_TIME, stoppingToken);
}
}
private async Task InitializeStateAsync()
{
using var scope = scopeFactory.CreateScope();
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
var campaigns = await headquartersService.GetInitiatedCampaignAsync();
foreach (var campaign in campaigns)
{
campaignManagementState.EnqueueCampaign(campaign);
}
}
}
}

View File

@ -0,0 +1,27 @@
using Hcs.WebApp.Data.Hcs;
using System.Collections.Concurrent;
namespace Hcs.WebApp.BackgroundServices
{
public class CampaignManagementState
{
private readonly ConcurrentQueue<Campaign> campaigns = new();
public event Action<Campaign> OnCampaignStarted;
public void EnqueueCampaign(Campaign campaign)
{
campaigns.Enqueue(campaign);
}
public bool TryDequeueCampaign(out Campaign campaign)
{
return campaigns.TryDequeue(out campaign);
}
public void InvokeOnCampaignStarted(Campaign campaign)
{
OnCampaignStarted?.Invoke(campaign);
}
}
}

View File

@ -0,0 +1,12 @@
using Hcs.WebApp.Data.Hcs;
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
{
public class ExportRequiredRegistryElementsManager_15_7_0_1(OperationExecutionState state, IServiceScopeFactory scopeFactory, Campaign campaign) : ManagerBase(state, scopeFactory, campaign)
{
public override async Task StartAsync(CancellationToken cancellationToken)
{
// TODO
}
}
}

View File

@ -0,0 +1,7 @@
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
{
public interface IManager
{
Task StartAsync(CancellationToken cancellationToken);
}
}

View File

@ -0,0 +1,13 @@
using Hcs.WebApp.Data.Hcs;
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
{
public abstract class ManagerBase(OperationExecutionState state, IServiceScopeFactory scopeFactory, Campaign campaign) : IManager
{
protected readonly OperationExecutionState state = state;
protected readonly IServiceScopeFactory scopeFactory = scopeFactory;
protected readonly Campaign campaign = campaign;
public abstract Task StartAsync(CancellationToken cancellationToken);
}
}

View File

@ -0,0 +1,21 @@
using Hcs.WebApp.Data.Hcs;
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
{
public class ManagerFactory(OperationExecutionState state, IServiceScopeFactory scopeFactory)
{
protected readonly OperationExecutionState state = state;
protected readonly IServiceScopeFactory scopeFactory = scopeFactory;
public IManager CreateManager(Campaign campaign)
{
switch (campaign.Type)
{
case Campaign.CampaignType.ExportRequiredRegistryElements_15_7_0_1:
return new ExportRequiredRegistryElementsManager_15_7_0_1(state, scopeFactory, campaign);
}
throw new NotImplementedException();
}
}
}

View File

@ -1,7 +1,7 @@
using Hcs.Broker;
using Hcs.Broker.Logger;
using Hcs.Broker.MessageCapturer;
using Hcs.WebApp.BackgroundServices.Executors;
using Hcs.WebApp.BackgroundServices.OperationExecutors;
using Hcs.WebApp.Config;
using Hcs.WebApp.Services;
@ -26,12 +26,14 @@ namespace Hcs.WebApp.BackgroundServices
InitializeClient();
var scope = scopeFactory.CreateScope();
var operationService = scope.ServiceProvider.GetRequiredService<OperationService>();
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
while (!stoppingToken.IsCancellationRequested)
{
while (state.TryDequeueOperation(out var operation))
{
if (stoppingToken.IsCancellationRequested) return;
var messageGuid = string.Empty;
try
{
@ -40,12 +42,13 @@ namespace Hcs.WebApp.BackgroundServices
}
catch
{
// TODO: Добавить таймауты и макс количество попыток выполнения операции
state.EnqueueOperation(operation);
}
if (!string.IsNullOrEmpty(messageGuid))
{
await operationService.SetOperationMessageGuidAsync(operation.Id, messageGuid);
await headquartersService.SetOperationMessageGuidAsync(operation.Id, messageGuid);
}
}
@ -56,9 +59,9 @@ namespace Hcs.WebApp.BackgroundServices
private async Task InitializeStateAsync()
{
using var scope = scopeFactory.CreateScope();
var operationService = scope.ServiceProvider.GetRequiredService<OperationService>();
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
var operations = await operationService.GetInitiatedOperationsAsync();
var operations = await headquartersService.GetInitiatedOperationsAsync();
foreach (var operation in operations)
{
state.EnqueueOperation(operation);

View File

@ -1,7 +1,7 @@
using Hcs.Broker;
using Hcs.WebApp.Data.Hcs;
namespace Hcs.WebApp.BackgroundServices.Executors
namespace Hcs.WebApp.BackgroundServices.OperationExecutors
{
public abstract class ExecutorBase(IClient client, Operation operation) : IExecutor
{

View File

@ -1,8 +1,8 @@
using Hcs.Broker;
using Hcs.WebApp.BackgroundServices.Executors._15_7_0_1.NsiCommon;
using Hcs.WebApp.BackgroundServices.OperationExecutors.NsiCommon;
using Hcs.WebApp.Data.Hcs;
namespace Hcs.WebApp.BackgroundServices.Executors
namespace Hcs.WebApp.BackgroundServices.OperationExecutors
{
public class ExecutorFactory
{
@ -10,8 +10,8 @@ namespace Hcs.WebApp.BackgroundServices.Executors
{
switch (operation.Type)
{
case Operation.OperationType.NsiCommon_15_7_0_1_ExportAllRegistryElements:
return new ExportAllRegistryElementsExecutor(client, operation);
case Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1:
return new ExportNsiItemExecutor_15_7_0_1(client, operation);
}
throw new NotImplementedException();

View File

@ -1,4 +1,4 @@
namespace Hcs.WebApp.BackgroundServices.Executors
namespace Hcs.WebApp.BackgroundServices.OperationExecutors
{
public interface IExecutor
{

View File

@ -1,9 +1,9 @@
using Hcs.Broker;
using Hcs.WebApp.Data.Hcs;
namespace Hcs.WebApp.BackgroundServices.Executors._15_7_0_1.NsiCommon
namespace Hcs.WebApp.BackgroundServices.OperationExecutors.NsiCommon
{
public class ExportAllRegistryElementsExecutor(IClient client, Operation operation) : ExecutorBase(client, operation)
public class ExportNsiItemExecutor_15_7_0_1(IClient client, Operation operation) : ExecutorBase(client, operation)
{
public override async Task<string> ExecuteAsync(CancellationToken cancellationToken)
{