Update campaign handling

This commit is contained in:
2025-10-27 16:56:08 +09:00
parent 445bfe8273
commit 6b3733001a
7 changed files with 86 additions and 11 deletions

View File

@ -8,16 +8,21 @@ namespace Hcs.WebApp.BackgroundServices
ManagerFactory managerFactory,
IServiceScopeFactory scopeFactory) : BackgroundService
{
private const int ITERATION_TIME = 1000;
private const int SLEEP_TIME = 30000;
private readonly CampaignManagementState campaignManagementState = campaignManagementState;
private readonly ManagerFactory managerFactory = managerFactory;
private readonly IServiceScopeFactory scopeFactory = scopeFactory;
private readonly List<IManager> managers = [];
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await InitializeStateAsync();
using var scope = scopeFactory.CreateScope();
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
while (!stoppingToken.IsCancellationRequested)
{
while (campaignManagementState.TryDequeueCampaign(out var campaign))
@ -28,15 +33,25 @@ namespace Hcs.WebApp.BackgroundServices
{
var manager = managerFactory.CreateManager(campaign);
await manager.StartAsync(stoppingToken);
managers.Add(manager);
}
catch
catch (Exception e)
{
// TODO: Добавить таймауты
campaignManagementState.EnqueueCampaign(campaign);
await headquartersService.SetCampaignEndedWithFail(campaign.Id, e.Message);
}
}
await Task.Delay(SLEEP_TIME, stoppingToken);
managers.RemoveAll(x => x.State == IManager.ManagerState.Ended);
if (managers.Count > 0)
{
await Task.Delay(ITERATION_TIME, stoppingToken);
}
else
{
await Task.Delay(SLEEP_TIME, stoppingToken);
}
}
}

View File

@ -2,6 +2,16 @@
{
public interface IManager
{
public enum ManagerState
{
Created,
Started,
Working,
Ended
}
public ManagerState State { get; }
Task StartAsync(CancellationToken cancellationToken);
}
}

View File

@ -8,6 +8,8 @@ namespace Hcs.WebApp.BackgroundServices.CampaignManagers
protected readonly IServiceScopeFactory scopeFactory = scopeFactory;
protected readonly Campaign campaign = campaign;
public IManager.ManagerState State { get; } = IManager.ManagerState.Created;
public abstract Task StartAsync(CancellationToken cancellationToken);
}
}

View File

@ -38,12 +38,12 @@ namespace Hcs.WebApp.BackgroundServices
try
{
var executor = executorFactory.CreateExecutor(client, operation);
await headquartersService.SetOperationStarted(operation.Id);
messageGuid = await executor.ExecuteAsync(stoppingToken);
}
catch
catch (Exception e)
{
// TODO: Добавить таймауты и макс количество попыток выполнения операции
state.EnqueueOperation(operation);
await headquartersService.SetOperationEndedWithFail(operation.Id, e.Message);
}
if (!string.IsNullOrEmpty(messageGuid))

View File

@ -15,10 +15,16 @@ namespace Hcs.WebApp.Data.Hcs
public string InitiatorId { get; set; }
public DateTime StartedAt { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? StartedAt { get; set; }
public DateTime? EndedAt { get; set; }
public int Step { get; set; }
public string FailureReason { get; set; }
public virtual ICollection<Operation> Operations { get; set; } = [];
[NotMapped]

View File

@ -17,12 +17,16 @@ namespace Hcs.WebApp.Data.Hcs
public OperationType Type { get; set; }
public DateTime StartedAt { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? StartedAt { get; set; }
public DateTime? EndedAt { get; set; }
public string? MessageGuid { get; set; }
public string FailureReason { get; set; }
public virtual ICollection<Registry> Registries { get; set; } = [];
[NotMapped]

View File

@ -36,7 +36,7 @@ namespace Hcs.WebApp.Services
{
Type = type,
InitiatorId = initiatorId,
StartedAt = DateTime.UtcNow
CreatedAt = DateTime.UtcNow
};
await context.Campaigns.AddAsync(campaign);
await context.SaveChangesAsync();
@ -50,13 +50,51 @@ namespace Hcs.WebApp.Services
{
CampaignId = campaignId,
Type = type,
StartedAt = DateTime.UtcNow
CreatedAt = DateTime.UtcNow
};
await context.Operations.AddAsync(operation);
await context.SaveChangesAsync();
return operation;
}
public async Task SetCampaignEndedWithFail(int campaignId, string failureReason)
{
using var context = factory.CreateDbContext();
var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
if (campaign != null)
{
campaign.EndedAt = DateTime.UtcNow;
campaign.FailureReason = failureReason;
await context.SaveChangesAsync();
}
}
public async Task SetOperationStarted(int operationId)
{
using var context = factory.CreateDbContext();
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 = factory.CreateDbContext();
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
if (operation != null)
{
operation.EndedAt = DateTime.UtcNow;
operation.FailureReason = failureReason;
await context.SaveChangesAsync();
}
}
public async Task SetOperationMessageGuidAsync(int operationId, string messageGuid)
{
using var context = factory.CreateDbContext();