Files
parr_api/PARR.GeneratorTemplates/Services/TemplateManager.cs

328 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.BLL.Domain.Mq;
using PARR.BLL.Helpers;
using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.Extensions;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using PARR.TemplateDistributor;
using System.Text.Json;
namespace PARR.GeneratorTemplates.Services
{
internal class TemplateManager : ITemplateManager
{
private readonly ITemplateService templateService;
private readonly IHostService hostService;
private readonly ILogger<TemplateManager> logger;
private readonly SettingsFromDb settingsFromDb;
private readonly IRobotConfigurationService robotConfigurationService;
private readonly IApplicationsInWorkService applicationsInWorkService;
private readonly ITemplateDistributor templateDistributor;
public TemplateManager(
ITemplateService templateService,
IHostService hostService,
ILogger<TemplateManager> logger,
SettingsFromDb settingsFromDb,
IRobotConfigurationService robotConfigurationService,
IApplicationsInWorkService applicationsInWorkService,
ITemplateDistributor templateDistributor
)
{
this.templateService = templateService;
this.hostService = hostService;
this.logger = logger;
this.settingsFromDb = settingsFromDb;
this.robotConfigurationService = robotConfigurationService;
this.applicationsInWorkService = applicationsInWorkService;
this.templateDistributor = templateDistributor;
}
public async Task CreateTemplates(GeneratorTemplateMq query)
{
//В таблице AppInWork находим РР, и смотрим ее рабочие группы. Затем по ним будем фильтровать хосты
var appInWorkWg = await applicationsInWorkService.Get()
.Include(t => t.WorkGroups)
.FirstAsync(t => t.ApplicationId == query.ApplicationId && t.WorkId == query.WorkId);
if (!appInWorkWg.WorkGroups.Any())
{
logger.LogWarning($"Не генерирую шаблоны. Нет рабочих групп у ApplicationInWork с id: {appInWorkWg.Id}");
return;
}
var workGroups = appInWorkWg.WorkGroups.ToList();
//Согласно параметрам, находит все ЭК в таблице Hosts.
//Далее проверяет есть ли такие шаблоны в таблице Templates, если нет, то создает, активирует и ставит статус Creating.
//Если такие шаблоны уже есть, ничего с ними не делает.
string ekPattern = SqlHelpers.RegexToLike(query.Ek);
// список хостов для создания шаблонов
var queryHosts = hostService.Get()
//.Include(t => t.WorkGroupItem)
.Include(t => t.ApplicationsInHosts)
.ThenInclude(t => t.Application).ThenInclude(t => t!.ApplicationsInWorks).ThenInclude(w => w.Work)
.Include(t => t.Templates)
.ThenInclude(w => w.ApplicationsInWork)
.Include(t => t.ResponseArea)
.Where(t =>
t.ApplicationsInHosts.Any(h =>
h.ApplicationId == query.ApplicationId
&& h.Application!.ApplicationsInWorks.Any(w => w.WorkId == query.WorkId)
)
&& EF.Functions.Like(t.Ek.ToLower(), ekPattern)
// смотрим что нет такого шаблона
&& t.Templates.Any(templ => templ.ApplicationsInWork!.WorkId == query.WorkId && templ.ApplicationsInWork.ApplicationId == query.ApplicationId) == false
// смотрим что у этих хостов есть нужные группы
//&& workGroups.Any(x => x.WorkGroupId == t.WorkGroupId)
);
// статус ЭК
if (query.StatusEk > 0)
queryHosts = queryHosts.Where(t => t.EkStatusCode == query.StatusEk);
var hosts = await queryHosts
.AsSplitQuery()
.ToListAsync();
// Исключаем хосты у которых нет нужных групп
hosts = hosts.Where(t => workGroups.Any(x => x.WorkGroupId == t.WorkGroupId)).ToList();
if (!hosts.Any())
{
logger.LogInformation($"Не найдено ЭК попадающих под условие: ${JsonSerializer.Serialize(query)}");
return;
}
// хосты группируем по РГ, чтоб потом распределить/рассчитать NextRun
var groupingHostByWg = hosts.GroupBy(t => t.WorkGroupId);
foreach (var group in groupingHostByWg)
{
var groupingHosts = group.ToList();
var templates = CreateQueryTemplates(groupingHosts, query);
//проверяем, что нет шаблонов с такими именами, исключаем их
templates = await ExcludeExistTemplatesAsync(templates);
if (!templates.Any())
continue;
//заполняем NextRun
templates = await templateDistributor.DistributeTemplateAsync(templates, appInWorkWg.Id, (Guid)group.Key!);
// сохраняем
foreach (var template in templates)
{
if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync(query.HistoryInitiator))
{
logger.LogError($"Ошибка при создании шаблона: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, HostId: {template.HostId}");
}
else
{
logger.LogInformation($"Создан шаблон: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, " +
$"HostId: {template.HostId}");
}
}
}
#region создавали шаблоны до того, как стали группировать по РГ
////Создаем шаблоны
//foreach (var host in hosts)
//{
// var appInWork = host.ApplicationsInHosts.FirstOrDefault(t => t.ApplicationId == query.ApplicationId)?.Application?.ApplicationsInWorks.FirstOrDefault(a => a.WorkId == query.WorkId);
// if (appInWork == null)
// {
// // такого не может быть, так как выполнился запрос при получении списка хостов, но мало ли
// logger.LogError($"Ошибка при создании шаблона. В таблице ApplicationsInWorks не найден Id согласно запроса WorkId: {query.WorkId}, ApplicationId: {query.ApplicationId}");
// return;
// }
// var template = new Template
// {
// Id = Guid.NewGuid(),
// //Name = TemplateHelpers.GenerateTemplateName("ЗО" ,settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name),
// //Генерить имя с полным именем работы и подстановкой ЭК
// //Name = TemplateHelpers.GenerateTemplateNameWithResponseArea(host.ResponseArea!.Name, settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name.ApplyShortcode(Constants.Shortcode.ShortcodeEnum.EK, host.Ek)),
// //Вместо полного имени работы, подставляется сокращенный суффикс или полное имя с ЭК если суффикса нет
// Name = TemplateHelpers.GenerateTemplateNameWithResponseArea(
// host.ResponseArea!.Name,
// settingsFromDb.TemplatePrefixName,
// host.Ek,
// appInWork.Work!.TemplateSuffix ?? appInWork.Work!.Name.ApplyShortcode(Constants.Shortcode.ShortcodeEnum.EK, host.Ek)
// ),
// IsActiveTemplate = query.IsActiveTemplate ?? false,
// IsActiveSchedule = query.IsActiveSchedule ?? false,
// ApplicationInWorkId = appInWork.Id,
// HostId = host.Id,
// //TODO:
// //NextRun = ???,
// LastRun = null
// };
// if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync())
// {
// logger.LogError($"Ошибка при создании шаблона: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, HostId: {template.HostId}");
// }
// else
// {
// logger.LogInformation($"Создан шаблон: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, " +
// $"HostId: {template.HostId}");
// }
//}
#endregion
}
/// <summary>
/// Исключаем существующие шаблоны из запроса на создание
/// </summary>
/// <param name="templates"></param>
/// <returns></returns>
private async Task<List<Template>> ExcludeExistTemplatesAsync(List<Template> templates)
{
// то ли костыль, то ли нет. Иногда попадают отфильтрованные шаблоны для создания, но они уже есть в БД. На всякий проверяем есть они или нет, и если есть, исключаем их из запроса.
// ищмем по имени такие шаблоны в БД и исключаем их
var existTemplates = await templateService.Get().Where(t => templates.Select(x => x.Name).Any(x => x == t.Name)).ToListAsync();
if (existTemplates.Any())
{
existTemplates.ForEach(item => logger.LogWarning($"Исключаем из запроса на создание шаблон, так как он уже есть в БД: {item.Name}"));
templates = templates.Where(t => !existTemplates.Any(x => x.Name == t.Name)).ToList();
}
return templates;
}
private List<Template> CreateQueryTemplates(List<Host> hosts, GeneratorTemplateMq query)
{
var templates = new List<Template>();
foreach (var host in hosts)
{
var appInWork = host.ApplicationsInHosts.FirstOrDefault(t => t.ApplicationId == query.ApplicationId)?.Application?.ApplicationsInWorks.FirstOrDefault(a => a.WorkId == query.WorkId);
if (appInWork == null)
{
// такого не может быть, так как выполнился запрос при получении списка хостов, но мало ли
logger.LogError($"Ошибка при создании шаблона. В таблице ApplicationsInWorks не найден Id согласно запроса WorkId: {query.WorkId}, ApplicationId: {query.ApplicationId}");
//return;
return templates;
}
var template = new Template
{
Id = Guid.NewGuid(),
//Name = TemplateHelpers.GenerateTemplateName("ЗО" ,settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name),
//Генерить имя с полным именем работы и подстановкой ЭК
//Name = TemplateHelpers.GenerateTemplateNameWithResponseArea(host.ResponseArea!.Name, settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name.ApplyShortcode(Constants.Shortcode.ShortcodeEnum.EK, host.Ek)),
//Вместо полного имени работы, подставляется сокращенный суффикс или полное имя с ЭК если суффикса нет
Name = TemplateHelpers.GenerateTemplateNameWithResponseArea(
host.ResponseArea!.Name,
settingsFromDb.TemplatePrefixName,
host.Ek,
appInWork.Work!.TemplateSuffix ?? appInWork.Work!.Name.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK, host.Ek)
),
IsActiveTemplate = query.IsActiveTemplate ?? false,
IsActiveSchedule = query.IsActiveSchedule ?? false,
ApplicationInWorkId = appInWork.Id,
HostId = host.Id,
// NextRun не задаем значение, его рассчитаем позже
//NextRun = ???,
LastRun = null
};
templates.Add(template);
}
return templates;
}
public async Task DeactivateTemplates(GeneratorTemplateMq query)
{
//TODO: !!! тут не учитываются поля query.IsActiveTemplate, query.IsActiveSchedule, просто все деактивируется. !!!
//В таблице AppInWork находим РР, и смотрим ее рабочие группы. Затем по ним будем фильтровать хосты
var appInWorkWg = await applicationsInWorkService.Get()
.Include(t => t.WorkGroups)
.FirstAsync(t => t.ApplicationId == query.ApplicationId && t.WorkId == query.WorkId);
if (!appInWorkWg.WorkGroups.Any())
{
logger.LogWarning($"Не деактивируем шаблоны. Нет рабочих групп у ApplicationInWork с id: {appInWorkWg.Id}");
return;
}
var workGroups = appInWorkWg.WorkGroups.ToList();
//Ищет все активные шаблоны согласно параметрам в таблице Templates, и деактивирует их. Меняем на статус Updating
// делаем sql формат для like из запроса.
string ekPattern = SqlHelpers.RegexToLike(query.Ek);
var queryTemplates = templateService.Get()
.Include(t => t.Host)
.Include(t => t.ApplicationsInWork)
.Include(t => t.RobotConfigurations)
.Where(t =>
(t.IsActiveTemplate == true || t.IsActiveSchedule == true)
&& t.ApplicationsInWork!.ApplicationId == query.ApplicationId
&& t.ApplicationsInWork!.WorkId == query.WorkId
&& EF.Functions.Like(t.Host!.Ek.ToLower(), ekPattern)
);
// статус ЭК
if (query.StatusEk > 0)
queryTemplates = queryTemplates.Where(t => t.Host!.EkStatusCode == query.StatusEk);
var existTemplates = await queryTemplates
.AsSplitQuery()
.ToListAsync();
// Исключаем хосты у которых нет нужных групп
existTemplates = existTemplates.Where(t => workGroups.Any(x => x.WorkGroupId == t.Host.WorkGroupId)).ToList();
if (!existTemplates.Any())
{
logger.LogInformation("Нет шаблонов для деактивации");
return;
}
existTemplates.ForEach(item =>
{
item.DateModified = DateTimeOffset.UtcNow;
if (item.IsActiveTemplate)
{
item.IsActiveTemplate = false;
//необходимо обновить шаблон
var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.TemplateOrder, ref item);
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, ref config);
}
if (item.IsActiveSchedule)
{
item.IsActiveSchedule = false;
//необходимо обновить расписание
var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, ref item);
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, ref config);
}
});
if (await templateService.CommitAsync(query.HistoryInitiator))
existTemplates.ForEach(item => logger.LogInformation($"Деактивирован шаблон: {item.Name}"));
else
existTemplates.ForEach(item => logger.LogError($"Ошибка при дактивации шаблона: {item.Name}"));
}
}
}