Add transaction support between services
This commit is contained in:
@ -20,24 +20,23 @@ namespace Hcs.WebApp.BackgroundServices
|
|||||||
{
|
{
|
||||||
await InitializeStateAsync();
|
await InitializeStateAsync();
|
||||||
|
|
||||||
using var scope = scopeFactory.CreateScope();
|
|
||||||
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
|
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
while (campaignManagementState.TryDequeueCampaign(out var campaign))
|
while (campaignManagementState.TryDequeueCampaign(out var campaign))
|
||||||
{
|
{
|
||||||
if (stoppingToken.IsCancellationRequested) return;
|
if (stoppingToken.IsCancellationRequested) return;
|
||||||
|
|
||||||
|
using var scope = scopeFactory.CreateScope();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var manager = managerFactory.CreateManager(campaign);
|
var manager = managerFactory.CreateManager(scope, campaign);
|
||||||
await manager.StartAsync(stoppingToken);
|
await manager.StartAsync(stoppingToken);
|
||||||
|
|
||||||
managers.Add(manager);
|
managers.Add(manager);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
|
||||||
await headquartersService.SetCampaignEndedWithFail(campaign.Id, e.Message);
|
await headquartersService.SetCampaignEndedWithFail(campaign.Id, e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,24 @@
|
|||||||
using Hcs.WebApp.Data.Hcs;
|
using Hcs.WebApp.Data.Hcs;
|
||||||
|
using Hcs.WebApp.Services;
|
||||||
|
|
||||||
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
|
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
|
||||||
{
|
{
|
||||||
public class ExportRequiredRegistryElementsManager_15_7_0_1(OperationExecutionState state, IServiceScopeFactory scopeFactory, Campaign campaign) : ManagerBase(state, scopeFactory, campaign)
|
public class ExportRequiredRegistryElementsManager_15_7_0_1(IServiceScope scope, OperationExecutionState state, Campaign campaign) : ManagerBase(scope, state, campaign)
|
||||||
{
|
{
|
||||||
public override async Task StartAsync(CancellationToken cancellationToken)
|
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
|
||||||
|
var registryService = scope.ServiceProvider.GetRequiredService<RegistryService>();
|
||||||
|
using var context = headquartersService.GetNewContext();
|
||||||
|
using var transaction = await context.Database.BeginTransactionAsync(cancellationToken);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
|
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
|
||||||
{
|
{
|
||||||
public abstract class ManagerBase(OperationExecutionState state, IServiceScopeFactory scopeFactory, Campaign campaign) : IManager
|
public abstract class ManagerBase(IServiceScope scope, OperationExecutionState state, Campaign campaign) : IManager
|
||||||
{
|
{
|
||||||
|
protected readonly IServiceScope scope = scope;
|
||||||
protected readonly OperationExecutionState state = state;
|
protected readonly OperationExecutionState state = state;
|
||||||
protected readonly IServiceScopeFactory scopeFactory = scopeFactory;
|
|
||||||
protected readonly Campaign campaign = campaign;
|
protected readonly Campaign campaign = campaign;
|
||||||
|
|
||||||
public IManager.ManagerState State { get; } = IManager.ManagerState.Created;
|
public IManager.ManagerState State { get; } = IManager.ManagerState.Created;
|
||||||
|
|||||||
@ -2,17 +2,16 @@
|
|||||||
|
|
||||||
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
|
namespace Hcs.WebApp.BackgroundServices.CampaignManagers
|
||||||
{
|
{
|
||||||
public class ManagerFactory(OperationExecutionState state, IServiceScopeFactory scopeFactory)
|
public class ManagerFactory(OperationExecutionState state)
|
||||||
{
|
{
|
||||||
protected readonly OperationExecutionState state = state;
|
protected readonly OperationExecutionState state = state;
|
||||||
protected readonly IServiceScopeFactory scopeFactory = scopeFactory;
|
|
||||||
|
|
||||||
public IManager CreateManager(Campaign campaign)
|
public IManager CreateManager(IServiceScope scope, Campaign campaign)
|
||||||
{
|
{
|
||||||
switch (campaign.Type)
|
switch (campaign.Type)
|
||||||
{
|
{
|
||||||
case Campaign.CampaignType.ExportRequiredRegistryElements_15_7_0_1:
|
case Campaign.CampaignType.ExportRequiredRegistryElements_15_7_0_1:
|
||||||
return new ExportRequiredRegistryElementsManager_15_7_0_1(state, scopeFactory, campaign);
|
return new ExportRequiredRegistryElementsManager_15_7_0_1(scope, state, campaign);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
@ -25,19 +25,18 @@ namespace Hcs.WebApp.BackgroundServices
|
|||||||
|
|
||||||
InitializeClient();
|
InitializeClient();
|
||||||
|
|
||||||
var scope = scopeFactory.CreateScope();
|
|
||||||
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
|
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
while (state.TryDequeueOperation(out var operation))
|
while (state.TryDequeueOperation(out var operation))
|
||||||
{
|
{
|
||||||
if (stoppingToken.IsCancellationRequested) return;
|
if (stoppingToken.IsCancellationRequested) return;
|
||||||
|
|
||||||
|
var scope = scopeFactory.CreateScope();
|
||||||
|
var headquartersService = scope.ServiceProvider.GetRequiredService<HeadquartersService>();
|
||||||
var messageGuid = string.Empty;
|
var messageGuid = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var executor = executorFactory.CreateExecutor(client, operation);
|
var executor = executorFactory.CreateExecutor(scope, client, operation);
|
||||||
await headquartersService.SetOperationStarted(operation.Id);
|
await headquartersService.SetOperationStarted(operation.Id);
|
||||||
messageGuid = await executor.ExecuteAsync(stoppingToken);
|
messageGuid = await executor.ExecuteAsync(stoppingToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,10 @@ using Hcs.WebApp.Data.Hcs;
|
|||||||
|
|
||||||
namespace Hcs.WebApp.BackgroundServices.OperationExecutors
|
namespace Hcs.WebApp.BackgroundServices.OperationExecutors
|
||||||
{
|
{
|
||||||
public abstract class ExecutorBase(IClient client, IServiceScopeFactory scopeFactory, Operation operation) : IExecutor
|
public abstract class ExecutorBase(IClient client, IServiceScope scope, Operation operation) : IExecutor
|
||||||
{
|
{
|
||||||
protected readonly IClient client = client;
|
protected readonly IClient client = client;
|
||||||
protected readonly IServiceScopeFactory scopeFactory = scopeFactory;
|
protected readonly IServiceScope scope = scope;
|
||||||
protected readonly Operation operation = operation;
|
protected readonly Operation operation = operation;
|
||||||
|
|
||||||
public abstract Task<string> ExecuteAsync(CancellationToken cancellationToken);
|
public abstract Task<string> ExecuteAsync(CancellationToken cancellationToken);
|
||||||
|
|||||||
@ -4,16 +4,14 @@ using Hcs.WebApp.Data.Hcs;
|
|||||||
|
|
||||||
namespace Hcs.WebApp.BackgroundServices.OperationExecutors
|
namespace Hcs.WebApp.BackgroundServices.OperationExecutors
|
||||||
{
|
{
|
||||||
public class ExecutorFactory(IServiceScopeFactory scopeFactory)
|
public class ExecutorFactory
|
||||||
{
|
{
|
||||||
protected readonly IServiceScopeFactory scopeFactory = scopeFactory;
|
public IExecutor CreateExecutor(IServiceScope scope, IClient client, Operation operation)
|
||||||
|
|
||||||
public IExecutor CreateExecutor(IClient client, Operation operation)
|
|
||||||
{
|
{
|
||||||
switch (operation.Type)
|
switch (operation.Type)
|
||||||
{
|
{
|
||||||
case Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1:
|
case Operation.OperationType.NsiCommon_ExportNsiItem_15_7_0_1:
|
||||||
return new ExportNsiItemExecutor_15_7_0_1(client, scopeFactory, operation);
|
return new ExportNsiItemExecutor_15_7_0_1(client, scope, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
@ -5,13 +5,12 @@ using Hcs.WebApp.Services;
|
|||||||
|
|
||||||
namespace Hcs.WebApp.BackgroundServices.OperationExecutors.NsiCommon
|
namespace Hcs.WebApp.BackgroundServices.OperationExecutors.NsiCommon
|
||||||
{
|
{
|
||||||
public class ExportNsiItemExecutor_15_7_0_1(IClient client, IServiceScopeFactory scopeFactory, Operation operation) : ExecutorBase(client, scopeFactory, operation)
|
public class ExportNsiItemExecutor_15_7_0_1(IClient client, IServiceScope scope, Operation operation) : ExecutorBase(client, scope, operation)
|
||||||
{
|
{
|
||||||
public override async Task<string> ExecuteAsync(CancellationToken cancellationToken)
|
public override async Task<string> ExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using var scope = scopeFactory.CreateScope();
|
|
||||||
var registryService = scope.ServiceProvider.GetRequiredService<RegistryService>();
|
var registryService = scope.ServiceProvider.GetRequiredService<RegistryService>();
|
||||||
var registry = await registryService.GetRegistryByOperationId(operation.Id);
|
var registry = await registryService.GetRegistryByOperationIdAsync(operation.Id);
|
||||||
return await client.NsiCommon.RequestExportNsiItemAsync(registry.Number, ListGroup.NSI, cancellationToken);
|
return await client.NsiCommon.RequestExportNsiItemAsync(registry.Number, ListGroup.NSI, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
Hcs.WebApp/Services/HcsServiceBase.cs
Normal file
15
Hcs.WebApp/Services/HcsServiceBase.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using Hcs.WebApp.Data.Hcs;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Hcs.WebApp.Services
|
||||||
|
{
|
||||||
|
public abstract class HcsServiceBase(IDbContextFactory<HcsDbContext> factory)
|
||||||
|
{
|
||||||
|
private readonly IDbContextFactory<HcsDbContext> factory = factory;
|
||||||
|
|
||||||
|
public HcsDbContext GetNewContext()
|
||||||
|
{
|
||||||
|
return factory.CreateDbContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,19 +3,17 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Hcs.WebApp.Services
|
namespace Hcs.WebApp.Services
|
||||||
{
|
{
|
||||||
public class HeadquartersService(IDbContextFactory<HcsDbContext> factory)
|
public class HeadquartersService(IDbContextFactory<HcsDbContext> factory) : HcsServiceBase(factory)
|
||||||
{
|
{
|
||||||
private readonly IDbContextFactory<HcsDbContext> factory = factory;
|
|
||||||
|
|
||||||
public async Task<bool> HasActiveCampaignAsync(Campaign.CampaignType type)
|
public async Task<bool> HasActiveCampaignAsync(Campaign.CampaignType type)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
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<IEnumerable<Campaign>> GetInitiatedCampaignAsync()
|
public async Task<IEnumerable<Campaign>> GetInitiatedCampaignAsync()
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
return await (from campaign in context.Campaigns
|
return await (from campaign in context.Campaigns
|
||||||
where !campaign.EndedAt.HasValue
|
where !campaign.EndedAt.HasValue
|
||||||
select campaign).ToListAsync();
|
select campaign).ToListAsync();
|
||||||
@ -23,7 +21,7 @@ namespace Hcs.WebApp.Services
|
|||||||
|
|
||||||
public async Task<IEnumerable<Operation>> GetInitiatedOperationsAsync()
|
public async Task<IEnumerable<Operation>> GetInitiatedOperationsAsync()
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
return await (from operation in context.Operations
|
return await (from operation in context.Operations
|
||||||
where !operation.EndedAt.HasValue && string.IsNullOrEmpty(operation.MessageGuid)
|
where !operation.EndedAt.HasValue && string.IsNullOrEmpty(operation.MessageGuid)
|
||||||
select operation).ToListAsync();
|
select operation).ToListAsync();
|
||||||
@ -31,7 +29,7 @@ namespace Hcs.WebApp.Services
|
|||||||
|
|
||||||
public async Task<Campaign> InitiateCampaignAsync(Campaign.CampaignType type, string initiatorId)
|
public async Task<Campaign> InitiateCampaignAsync(Campaign.CampaignType type, string initiatorId)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
var campaign = new Campaign()
|
var campaign = new Campaign()
|
||||||
{
|
{
|
||||||
Type = type,
|
Type = type,
|
||||||
@ -45,7 +43,7 @@ namespace Hcs.WebApp.Services
|
|||||||
|
|
||||||
public async Task<Operation> InitiateOperationAsync(int campaignId, Operation.OperationType type)
|
public async Task<Operation> InitiateOperationAsync(int campaignId, Operation.OperationType type)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
var operation = new Operation()
|
var operation = new Operation()
|
||||||
{
|
{
|
||||||
CampaignId = campaignId,
|
CampaignId = campaignId,
|
||||||
@ -59,7 +57,7 @@ namespace Hcs.WebApp.Services
|
|||||||
|
|
||||||
public async Task SetCampaignEndedWithFail(int campaignId, string failureReason)
|
public async Task SetCampaignEndedWithFail(int campaignId, string failureReason)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
|
var campaign = await context.Campaigns.FirstOrDefaultAsync(x => x.Id == campaignId);
|
||||||
if (campaign != null)
|
if (campaign != null)
|
||||||
{
|
{
|
||||||
@ -72,7 +70,7 @@ namespace Hcs.WebApp.Services
|
|||||||
|
|
||||||
public async Task SetOperationStarted(int operationId)
|
public async Task SetOperationStarted(int operationId)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
|
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
|
||||||
if (operation != null)
|
if (operation != null)
|
||||||
{
|
{
|
||||||
@ -84,7 +82,7 @@ namespace Hcs.WebApp.Services
|
|||||||
|
|
||||||
public async Task SetOperationEndedWithFail(int operationId, string failureReason)
|
public async Task SetOperationEndedWithFail(int operationId, string failureReason)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
|
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
|
||||||
if (operation != null)
|
if (operation != null)
|
||||||
{
|
{
|
||||||
@ -97,7 +95,7 @@ namespace Hcs.WebApp.Services
|
|||||||
|
|
||||||
public async Task SetOperationMessageGuidAsync(int operationId, string messageGuid)
|
public async Task SetOperationMessageGuidAsync(int operationId, string messageGuid)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
|
var operation = await context.Operations.FirstOrDefaultAsync(x => x.Id == operationId);
|
||||||
if (operation != null)
|
if (operation != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,22 +3,34 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Hcs.WebApp.Services
|
namespace Hcs.WebApp.Services
|
||||||
{
|
{
|
||||||
public class RegistryService(IDbContextFactory<HcsDbContext> factory)
|
public class RegistryService(IDbContextFactory<HcsDbContext> factory) : HcsServiceBase(factory)
|
||||||
{
|
{
|
||||||
private readonly IDbContextFactory<HcsDbContext> factory = factory;
|
|
||||||
|
|
||||||
public async Task<IEnumerable<Registry>> GetAllRegistriesAsync(bool isCommon)
|
public async Task<IEnumerable<Registry>> GetAllRegistriesAsync(bool isCommon)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
return await (from registry in context.Registries
|
return await (from registry in context.Registries
|
||||||
where registry.IsCommon == isCommon
|
where registry.IsCommon == isCommon
|
||||||
select registry).ToListAsync();
|
select registry).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Registry> GetRegistryByOperationId(int operationId)
|
public async Task<Registry> GetRegistryByOperationIdAsync(int operationId)
|
||||||
{
|
{
|
||||||
using var context = factory.CreateDbContext();
|
using var context = GetNewContext();
|
||||||
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)
|
||||||
|
{
|
||||||
|
using var context = GetNewContext();
|
||||||
|
return await (from registry in context.Registries
|
||||||
|
where registry.LastSyncOperationId == operationId
|
||||||
|
select registry).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SetOperationIdToAllRegistries(HcsDbContext context, int operationId)
|
||||||
|
{
|
||||||
|
await context.Registries.ForEachAsync(x => x.LastSyncOperationId = operationId);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user