328 lines
18 KiB
C#
328 lines
18 KiB
C#
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}"));
|
||
}
|
||
}
|
||
}
|