Complete campaign flow

This commit is contained in:
2025-10-28 15:03:54 +09:00
parent 9e526c54fa
commit fa485918cc
7 changed files with 132 additions and 40 deletions

View File

@ -30,17 +30,22 @@ namespace Hcs.WebApp.BackgroundServices
try try
{ {
var manager = managerFactory.CreateManager(scope, campaign); var manager = managerFactory.CreateManager(scope, campaign);
await manager.StartAsync(stoppingToken); await manager.StartAsync();
managers.Add(manager); managers.Add(manager);
} }
catch (Exception e) catch (Exception e)
{ {
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>(); var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
await headquartersService.SetCampaignEndedWithFail(campaign.Id, e.Message); await headquartersService.SetCampaignEndedWithFailAsync(campaign.Id, e.Message);
} }
} }
foreach (var manager in managers)
{
await manager.CheckStateAsync();
}
managers.RemoveAll(x => x.State == IManager.ManagerState.Ended); managers.RemoveAll(x => x.State == IManager.ManagerState.Ended);
if (managers.Count > 0) if (managers.Count > 0)

View File

@ -3,22 +3,57 @@ using Hcs.WebApp.Services;
namespace Hcs.WebApp.BackgroundServices.CampaignManagers namespace Hcs.WebApp.BackgroundServices.CampaignManagers
{ {
public class ExportRequiredRegistryElementsManager_15_7_0_1(IServiceScope scope, OperationExecutionState state, Campaign campaign) : ManagerBase(scope, state, campaign) public class ExportRequiredRegistryElementsManager_15_7_0_1(IServiceScope scope, OperationExecutionState operationExecutionState, Campaign campaign) : ManagerBase(scope, operationExecutionState, campaign)
{ {
public override async Task StartAsync(CancellationToken cancellationToken) public override async Task StartAsync()
{ {
if (campaign.Step > 0) return;
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>(); var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
var registryService = scope.ServiceProvider.GetRequiredService<RegistryService>(); var registryService = scope.ServiceProvider.GetRequiredService<RegistryService>();
using var context = headquartersService.GetNewContext(); using var context = headquartersService.GetNewContext();
using var transaction = await context.Database.BeginTransactionAsync(cancellationToken); using var transaction = await context.Database.BeginTransactionAsync();
IEnumerable<Operation> operations = null;
try try
{ {
// TODO await headquartersService.SetCampaignStartedAsync(context, campaign.Id);
await headquartersService.SetCampaignStepAsync(context, campaign.Id, 1);
var registryCount = await registryService.GetRegistryCountAsync(context);
operations = await headquartersService.InitiateOperationsAsync(context, registryCount, campaign.Id, Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1);
await registryService.SetOperationsToRegistriesAsync(context, operations);
await transaction.CommitAsync();
} }
catch catch
{ {
transaction?.Rollback();
throw; throw;
} }
if (operations != null)
{
foreach (var operation in operations)
{
operationExecutionState.EnqueueOperation(operation);
}
}
State = IManager.ManagerState.Started;
}
public override async Task CheckStateAsync()
{
if (State == IManager.ManagerState.Started)
{
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
var hasActiveOperations = await headquartersService.HasActiveOperationsAsync(campaign.Id);
if (!hasActiveOperations)
{
State = IManager.ManagerState.Ended;
await headquartersService.SetCampaignEndedAsync(campaign.Id);
}
}
} }
} }
} }

View File

@ -6,12 +6,13 @@
{ {
Created, Created,
Started, Started,
Working,
Ended Ended
} }
public ManagerState State { get; } public ManagerState State { get; }
Task StartAsync(CancellationToken cancellationToken); Task StartAsync();
Task CheckStateAsync();
} }
} }

View File

@ -2,14 +2,16 @@
namespace Hcs.WebApp.BackgroundServices.CampaignManagers namespace Hcs.WebApp.BackgroundServices.CampaignManagers
{ {
public abstract class ManagerBase(IServiceScope scope, OperationExecutionState state, Campaign campaign) : IManager public abstract class ManagerBase(IServiceScope scope, OperationExecutionState operationExecutionState, Campaign campaign) : IManager
{ {
protected readonly IServiceScope scope = scope; protected readonly IServiceScope scope = scope;
protected readonly OperationExecutionState state = state; protected readonly OperationExecutionState operationExecutionState = operationExecutionState;
protected readonly Campaign campaign = campaign; protected readonly Campaign campaign = campaign;
public IManager.ManagerState State { get; } = IManager.ManagerState.Created; public IManager.ManagerState State { get; protected set; } = IManager.ManagerState.Created;
public abstract Task StartAsync(CancellationToken cancellationToken); public abstract Task StartAsync();
public abstract Task CheckStateAsync();
} }
} }

View File

@ -37,12 +37,12 @@ namespace Hcs.WebApp.BackgroundServices
try try
{ {
var executor = executorFactory.CreateExecutor(scope, client, operation); var executor = executorFactory.CreateExecutor(scope, client, operation);
await headquartersService.SetOperationStarted(operation.Id); await headquartersService.SetOperationStartedAsync(operation.Id);
messageGuid = await executor.ExecuteAsync(stoppingToken); messageGuid = await executor.ExecuteAsync(stoppingToken);
} }
catch (Exception e) catch (Exception e)
{ {
await headquartersService.SetOperationEndedWithFail(operation.Id, e.Message); await headquartersService.SetOperationEndedWithFailAsync(operation.Id, e.Message);
} }
if (!string.IsNullOrEmpty(messageGuid)) if (!string.IsNullOrEmpty(messageGuid))

View File

@ -11,6 +11,12 @@ namespace Hcs.WebApp.Services
return await context.Campaigns.AnyAsync(x => x.Type == type && !x.EndedAt.HasValue); return await context.Campaigns.AnyAsync(x => x.Type == type && !x.EndedAt.HasValue);
} }
public async Task<bool> HasActiveOperationsAsync(int campaignId)
{
using var context = GetNewContext();
return await context.Operations.CountAsync(x => x.CampaignId == campaignId && !x.EndedAt.HasValue) > 0;
}
public async Task<IEnumerable<Campaign>> GetInitiatedCampaignAsync() public async Task<IEnumerable<Campaign>> GetInitiatedCampaignAsync()
{ {
using var context = GetNewContext(); using var context = GetNewContext();
@ -41,21 +47,59 @@ namespace Hcs.WebApp.Services
return campaign; return campaign;
} }
public async Task<Operation> InitiateOperationAsync(int campaignId, Operation.OperationType type) public async Task<IEnumerable<Operation>> InitiateOperationsAsync(HcsDbContext context, int count, int campaignId, Operation.OperationType type)
{ {
using var context = GetNewContext(); var operations = new List<Operation>();
var operation = new Operation() for (var i = 0; i < count; i++)
{ {
CampaignId = campaignId, operations.Add(new Operation()
Type = type, {
CreatedAt = DateTime.UtcNow CampaignId = campaignId,
}; Type = type,
await context.Operations.AddAsync(operation); CreatedAt = DateTime.UtcNow
});
}
await context.Operations.AddRangeAsync(operations);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
return operation; return operations;
} }
public async Task SetCampaignEndedWithFail(int campaignId, string failureReason) public async Task SetCampaignStartedAsync(HcsDbContext context, int campaignId)
{
var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
if (campaign != null)
{
campaign.StartedAt = DateTime.UtcNow;
await context.SaveChangesAsync();
}
}
public async Task SetOperationStartedAsync(int operationId)
{
using var context = GetNewContext();
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
if (operation != null)
{
operation.StartedAt = DateTime.UtcNow;
await context.SaveChangesAsync();
}
}
public async Task SetCampaignEndedAsync(int campaignId)
{
using var context = GetNewContext();
var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
if (campaign != null)
{
campaign.EndedAt = DateTime.UtcNow;
await context.SaveChangesAsync();
}
}
public async Task SetCampaignEndedWithFailAsync(int campaignId, string failureReason)
{ {
using var context = GetNewContext(); using var context = GetNewContext();
var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId); var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
@ -68,19 +112,7 @@ namespace Hcs.WebApp.Services
} }
} }
public async Task SetOperationStarted(int operationId) public async Task SetOperationEndedWithFailAsync(int operationId, string failureReason)
{
using var context = GetNewContext();
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
if (operation != null)
{
operation.StartedAt = DateTime.UtcNow;
await context.SaveChangesAsync();
}
}
public async Task SetOperationEndedWithFail(int operationId, string failureReason)
{ {
using var context = GetNewContext(); using var context = GetNewContext();
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId); var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
@ -104,5 +136,16 @@ namespace Hcs.WebApp.Services
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
} }
public async Task SetCampaignStepAsync(HcsDbContext context, int campaignId, int step)
{
var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
if (campaign != null)
{
campaign.Step = step;
await context.SaveChangesAsync();
}
}
} }
} }

View File

@ -5,6 +5,11 @@ namespace Hcs.WebApp.Services
{ {
public class RegistryService(IDbContextFactory<HcsDbContext> factory) : HcsServiceBase(factory) public class RegistryService(IDbContextFactory<HcsDbContext> factory) : HcsServiceBase(factory)
{ {
public async Task<int> GetRegistryCountAsync(HcsDbContext context)
{
return await context.Registries.CountAsync();
}
public async Task<IEnumerable<Registry>> GetAllRegistriesAsync(bool isCommon) public async Task<IEnumerable<Registry>> GetAllRegistriesAsync(bool isCommon)
{ {
using var context = GetNewContext(); using var context = GetNewContext();
@ -19,7 +24,7 @@ namespace Hcs.WebApp.Services
return await context.Registries.SingleAsync(x => x.LastSyncOperationId == operationId); return await context.Registries.SingleAsync(x => x.LastSyncOperationId == operationId);
} }
public async Task<IEnumerable<Registry>> GetRegistriesByOperationId(int operationId) public async Task<IEnumerable<Registry>> GetRegistriesByOperationIdAsync(int operationId)
{ {
using var context = GetNewContext(); using var context = GetNewContext();
return await (from registry in context.Registries return await (from registry in context.Registries
@ -27,9 +32,10 @@ namespace Hcs.WebApp.Services
select registry).ToListAsync(); select registry).ToListAsync();
} }
public async Task SetOperationIdToAllRegistries(HcsDbContext context, int operationId) public async Task SetOperationsToRegistriesAsync(HcsDbContext context, IEnumerable<Operation> operations)
{ {
await context.Registries.ForEachAsync(x => x.LastSyncOperationId = operationId); var queue = new Queue<Operation>(operations);
await context.Registries.ForEachAsync(x => x.LastSyncOperationId = queue.Dequeue().Id);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
} }