feat(templateActivator): Методы чтения MQ, обновления состояний шаблонов и расписаний, обновления заданий роботов

This commit is contained in:
Mikhail Kuznetsov
2024-07-25 17:23:08 +10:00
parent 7220bdd8af
commit 014c760225
13 changed files with 357 additions and 18 deletions

View File

@@ -35,14 +35,14 @@
/// </summary> /// </summary>
DeactivateAllSchedules = 5, DeactivateAllSchedules = 5,
/// /// <summary>
/// Активировать все расписания у которых активированы шаблоны /// Активировать все расписания у которых активированы шаблоны
/// /// </summary>
ActivateSchedulesWithActiveTemplates = 6, ActivateSchedulesWithActiveTemplates = 6,
/// /// <summary>
/// Деактивировать все расписания у которых деактивированы шаблоны /// Деактивировать все расписания у которых деактивированы шаблоны
/// /// </summary>
DeactivateSchedulesWithDeactivationTemplates = 7 DeactivateSchedulesWithDeactivationTemplates = 7

View File

@@ -0,0 +1,7 @@
namespace PARR.TemplateActivator;
public interface IMqTemplateActivator
{
void Start();
void Stop();
}

View File

@@ -0,0 +1,8 @@
using PARR.Constants;
namespace PARR.TemplateActivator;
public interface ITemplateActivator
{
Task ChangeStateAsync(Guid applicationInWorkId, TemplateActivatorActionsEnum action);
}

View File

@@ -0,0 +1,71 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces;
using PARR.Constants;
namespace PARR.TemplateActivator;
internal class MqTemplateActivator : IMqTemplateActivator
{
private readonly MqSettings mqSettings;
private readonly IMqService mqService;
private readonly ILogger<MqTemplateActivator> logger;
private readonly ITransformService transformService;
private readonly IValidatorService validatorService;
private readonly IServiceProvider serviceProvider;
public MqTemplateActivator(
MqSettings mqSettings,
IMqService mqService,
ILogger<MqTemplateActivator> logger,
ITransformService transformService,
IValidatorService validatorService,
IServiceProvider serviceProvider
)
{
this.mqSettings = mqSettings;
this.mqService = mqService;
this.logger = logger;
this.transformService = transformService;
this.validatorService = validatorService;
this.serviceProvider = serviceProvider;
}
public void Start()
{
var isConnected = mqService.InitConsumer(mqSettings, UpdateTemplateStatusAsync);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
}
private async Task UpdateTemplateStatusAsync(string msg)
{
logger.LogInformation($"{this.GetType().Name}. Получили запрос: {msg}");
var query = transformService.GetModelFromJson<TemplateActivatorMq>(msg);
if (query == null)
return;
if (!await validatorService.IsValidApplicationInWorkAsync(query.ApplicationInWorkId))
{
logger.LogError($"{this.GetType().Name}. Некорректные параметры регламентной работы {nameof(query.ApplicationInWorkId)}: {query.ApplicationInWorkId}");
return;
}
using (var scope = serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetService<ITemplateActivator>();
if (service == null)
throw new Exception($"{this.GetType().Name}. Не найден сервис: {nameof(service.GetType)}");
await service.ChangeStateAsync(query.ApplicationInWorkId, query.Action);
}
}
public void Stop()
{
mqService.Dispose();
}
}

View File

@@ -0,0 +1,8 @@
using PARR.Constants;
namespace PARR.TemplateActivator;
internal interface IValidatorService
{
Task<bool> IsValidApplicationInWorkAsync(Guid applicationInWorkId);
}

View File

@@ -0,0 +1,42 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PARR.Constants;
using PARR.DAL.Services.Interfaces;
namespace PARR.TemplateActivator;
internal class ValidatorService : IValidatorService
{
private readonly IServiceProvider serviceProvider;
private readonly ILogger<ValidatorService> logger;
public ValidatorService(IServiceProvider serviceProvider,
ILogger<ValidatorService> logger
)
{
this.serviceProvider = serviceProvider;
this.logger = logger;
}
public async Task<bool> IsValidApplicationInWorkAsync(Guid applicationInWorkId)
{
using (var scope = serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetService<IApplicationsInWorkService>();
if (service == null)
throw new Exception($"Не найден сервис: {nameof(IApplicationsInWorkService)}");
var appInWork = await service.Get()
.FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
if (appInWork == null)
{
logger.LogError($"Не найдена регалментная работа {nameof(applicationInWorkId)}: {applicationInWorkId}");
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,12 @@
using PARR.BLL.Contracts.Interfaces;
namespace PARR.TemplateActivator;
internal class MqSettings : IMqSettings
{
public string HostName { get; set; } = string.Empty;
public string QueueName { get; set; } = string.Empty;
public string User { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,113 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
namespace PARR.TemplateActivator;
internal class TemplateActivator : ITemplateActivator
{
private readonly ILogger<TemplateActivator> logger;
private readonly ITemplateService templateService;
private readonly IRobotConfigurationService robotConfigurationService;
public TemplateActivator(
ILogger<TemplateActivator> logger,
ITemplateService templateService,
IRobotConfigurationService robotConfigurationService
)
{
this.logger = logger;
this.templateService = templateService;
this.robotConfigurationService = robotConfigurationService;
}
public async Task ChangeStateAsync(Guid applicationInWorkId, TemplateActivatorActionsEnum action)
{
var query = templateService.Get()
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Where(t => t.ApplicationInWorkId == applicationInWorkId);
var changes = 0;
switch (action)
{
case TemplateActivatorActionsEnum.ActivateAllTemplates:
query = query.Where(t => !t.IsActiveTemplate);
changes = await UpdateTemplateStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.ActivateTemplatesWithActiveSchedules:
query = query.Where(t => !t.IsActiveTemplate && t.IsActiveSchedule);
changes = await UpdateTemplateStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.DeactivateAllTemplates:
query = query.Where(t => t.IsActiveTemplate);
changes = await UpdateTemplateStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.DeactivateTemplatesWithDeactivationSchedules:
query = query.Where(t => !t.IsActiveTemplate && !t.IsActiveSchedule);
changes = await UpdateTemplateStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.ActivateAllSchedules:
query = query.Where(t => !t.IsActiveSchedule);
changes = await UpdateScheduleStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.DeactivateAllSchedules:
query = query.Where(t => t.IsActiveSchedule);
changes = await UpdateScheduleStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.ActivateSchedulesWithActiveTemplates:
query = query.Where(t => t.IsActiveTemplate && !t.IsActiveSchedule);
changes = await UpdateScheduleStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.DeactivateSchedulesWithDeactivationTemplates:
query = query.Where(t => !t.IsActiveTemplate);
changes = await UpdateScheduleStateAsync(query, false);
break;
default:
break;
}
if (changes > 0 && !await templateService.CommitAsync())
logger.LogError($"{this.GetType} не удалось записать измения состояний шаблонов и расписаний регламентной работы {applicationInWorkId}");
}
private async Task<int> UpdateScheduleStateAsync(IQueryable<Template> query, bool newState)
{
var templates = await query.Select(t => t).ToListAsync();
if (templates.Any())
templates.ForEach(t =>
{
t.IsActiveSchedule = newState;
UpdateRobotConfiguration(RobotsEnum.ScheduleOrder, t);
});
templates.ForEach(t => t.IsActiveSchedule = newState);
return templates.Count;
}
private async Task<int> UpdateTemplateStateAsync(IQueryable<Template> query, bool newState)
{
var templates = await query.Select(t => t).ToListAsync();
if (templates.Any())
templates.ForEach(t =>
{
t.IsActiveTemplate = newState;
UpdateRobotConfiguration(RobotsEnum.TemplateOrder, t);
});
return templates.Count;
}
private void UpdateRobotConfiguration(RobotsEnum robotsEnum, Template t)
{
var config = robotConfigurationService.GetFromTemplateByRobotCode(robotsEnum, ref t);
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, ref config);
}
}

View File

@@ -0,0 +1,24 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using PARR.BLL;
using PARR.DAL;
namespace PARR.TemplateActivator;
public static class TemplateActivatorInstaller
{
public static void InstallTemplateActivatorSerivces(this IServiceCollection services, IConfiguration configuration)
{
services.InstallBllServices(configuration);
services.InstallDalServices(configuration);
var mqSettings = new MqSettings();
configuration.GetSection(nameof(MqSettings)).Bind(mqSettings);
services.AddSingleton(mqSettings);
services.AddTransient<ITemplateActivator, TemplateActivator>();
services.AddTransient<IMqTemplateActivator, MqTemplateActivator>();
services.AddTransient<IValidatorService, ValidatorService>();
}
}

View File

@@ -1,10 +1,29 @@
using Serilog;
using Elastic.CommonSchema.Serilog;
using PARR.TemplateActivatorWorker; using PARR.TemplateActivatorWorker;
using PARR.TemplateActivator;
IHost host = Host.CreateDefaultBuilder(args) var builder = Host.CreateApplicationBuilder();
.ConfigureServices(services =>
builder.Services.AddLogging(config =>
{ {
services.AddHostedService<Worker>(); config.ClearProviders();
})
.Build();
var logger = new LoggerConfiguration();
if (builder.Environment.IsProduction())
logger.WriteTo.Console(new EcsTextFormatter());
else
logger.WriteTo.Console();
logger.ReadFrom.Configuration(builder.Configuration);
config.AddSerilog(logger.CreateLogger());
});
builder.Services.InstallTemplateActivatorSerivces(builder.Configuration);
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run(); host.Run();

View File

@@ -1,23 +1,28 @@
using PARR.TemplateActivator;
namespace PARR.TemplateActivatorWorker namespace PARR.TemplateActivatorWorker
{ {
public class Worker : BackgroundService public class Worker : BackgroundService
{ {
private readonly ILogger<Worker> _logger; private readonly ILogger<Worker> _logger;
private readonly IMqTemplateActivator mqTemplateActivator;
public Worker(ILogger<Worker> logger) public Worker(ILogger<Worker> logger, IMqTemplateActivator mqTemplateActivator)
{ {
_logger = logger; _logger = logger;
this.mqTemplateActivator = mqTemplateActivator;
} }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{ {
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: TemplateActivatorMq mqTemplateActivator.Start();
}
//while (!stoppingToken.IsCancellationRequested) public override Task StopAsync(CancellationToken cancellationToken)
//{ {
// _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); mqTemplateActivator.Stop();
// await Task.Delay(1000, stoppingToken);
//} return base.StopAsync(cancellationToken);
} }
} }
} }

View File

@@ -4,5 +4,8 @@
"Default": "Information", "Default": "Information",
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
},
"MqSettings": {
"HostName": "10.99.253.216"
} }
} }

View File

@@ -1,8 +1,35 @@
{ {
"ConnectionStrings": {
"DefaultConnection": "Server=10.99.253.184;Database=parr;User Id=app_parr; Password=PosdfkhT&)%sdfligL&%5546;"
},
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
},
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Debug"
}
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "log/log-.txt",
"rollingInterval": "Day"
}
}
]
},
"MqSettings": {
"HostName": "parr-rabbitmq",
"QueueName": "parr-template-activator",
"User": "template_activator_reader",
"Password": "KUYGFskdjhgf&^%sdfg"
} }
} }