Files
parr_api/PARR.TemplateActivator/TemplateActivator.cs

302 lines
15 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.Helpers;
using PARR.Common.Domain;
using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using System.Threading.Channels;
using System.Threading.Tasks;
namespace PARR.TemplateActivator;
internal class TemplateActivator : ITemplateActivator
{
private readonly ILogger<TemplateActivator> logger;
private readonly ITemplateService templateService;
private readonly IRobotConfigurationService robotConfigurationService;
private readonly IJobAutoControlService jobAutoControlService;
private readonly IApplicationsInWorkService applicationsInWorkService;
public TemplateActivator(
ILogger<TemplateActivator> logger,
ITemplateService templateService,
IRobotConfigurationService robotConfigurationService,
IJobAutoControlService jobAutoControlService,
IApplicationsInWorkService applicationsInWorkService
)
{
this.logger = logger;
this.templateService = templateService;
this.robotConfigurationService = robotConfigurationService;
this.jobAutoControlService = jobAutoControlService;
this.applicationsInWorkService = applicationsInWorkService;
}
public async Task ChangeStateAsync(Guid applicationInWorkId, TemplateActivatorActionsEnum action, IHistoryInitiator? historyInitiator)
{
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:
logger.LogInformation($"Получен запрос на активацию всех шаблонов");
query = query.Where(t => !t.IsActiveTemplate);
changes = await UpdateTemplateStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.ActivateTemplatesWithActiveSchedules:
logger.LogInformation($"Получен запрос на активацию всех шаблонов, у которых активировано расписание");
query = query.Where(t => !t.IsActiveTemplate && t.IsActiveSchedule);
changes = await UpdateTemplateStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.DeactivateAllTemplates:
logger.LogInformation($"Получен запрос на деактивацию всех шаблонов");
query = query.Where(t => t.IsActiveTemplate);
changes = await UpdateTemplateStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.DeactivateTemplatesWithDeactivationSchedules:
logger.LogInformation($"Получен запрос на деактивацию всех шаблонов, у которых неактивированы расписания");
query = query.Where(t => t.IsActiveTemplate && !t.IsActiveSchedule);
changes = await UpdateTemplateStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.ActivateAllSchedules:
logger.LogInformation($"Получен запрос на активацию всех расписаний");
query = query.Where(t => !t.IsActiveSchedule);
changes = await UpdateScheduleStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.DeactivateAllSchedules:
logger.LogInformation($"Получен запрос на деактивацию всех расписаний");
query = query.Where(t => t.IsActiveSchedule);
changes = await UpdateScheduleStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.ActivateSchedulesWithActiveTemplates:
logger.LogInformation($"Получен запрос на активацию всех расписаний, у которых активированы шаблоны");
query = query.Where(t => t.IsActiveTemplate && !t.IsActiveSchedule);
changes = await UpdateScheduleStateAsync(query, true);
break;
case TemplateActivatorActionsEnum.DeactivateSchedulesWithDeactivationTemplates:
logger.LogInformation($"Получен запрос на деактивацию всех расписаний, у которых неактивированы шаблоны");
query = query.Where(t => !t.IsActiveTemplate && t.IsActiveSchedule);
changes = await UpdateScheduleStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.DeactivateSchedulesWithTemplateSyncErrors:
logger.LogInformation($"Получен запрос на деактивацию всех расписаний, у которых шаблоны синхронизированы с ошибкой");
query = query.Where(t => t.IsActiveTemplate &&
t.RobotConfigurations.Any(t =>
t.RobotCode == (int)RobotsEnum.TemplateOrder &&
t.RobotStatusCode == (int)RobotStatusEnum.Error)
);
changes = await UpdateScheduleStateAsync(query, false);
break;
case TemplateActivatorActionsEnum.DeactivateAllForAutoControl:
logger.LogInformation($"Получен запрос на деактивацию шаблонов и расписаний, для ЭК неудовлетворяющим условиям автоконтроля");
changes = await CoordinateJobsWithAutoControlAsync(applicationInWorkId, query, false);
break;
case TemplateActivatorActionsEnum.ActivateAllForAutoControl:
logger.LogInformation($"Получен запрос на активацию шаблонов и расписаний, для ЭК удовлетворяющим условиям автоконтроля");
changes = await CoordinateJobsWithAutoControlAsync(applicationInWorkId, query, true);
break;
default:
break;
}
if (historyInitiator != null)
{
historyInitiator.InitiatorComment += $" Action: {action.ToString()}";
historyInitiator.InitiatorComment = historyInitiator.InitiatorComment.Trim();
}
if (changes > 0 && !await templateService.CommitAsync(historyInitiator))
logger.LogError($"{GetType().Name} не удалось записать измения в БД о новых состояниях шаблонов и расписаний регламентной работы Id {applicationInWorkId}");
logger.LogDebug($"{GetType().Name} изменил состояние шаблонов/расписаний({changes}) регламентной работы Id {applicationInWorkId}");
}
private async Task<int> CoordinateJobsWithAutoControlAsync(Guid applicationInWorkId, IQueryable<Template> query, bool isActivate)
{
var changes = 0;
//Добавляем информацию о рабочих группах для возможности их фильтрации
query = query.Include(t => t.Host).ThenInclude(h => h!.WorkGroup);
//Получаем настройки авто-контроля
var jobAutoControlSettings = await GetJobAutoControlSettingsAsync(applicationInWorkId);
if (jobAutoControlSettings == null)
return 0;
var trueEkStatuses = jobAutoControlSettings.JobAutoControlInEkStatuses;
var trueMasks = jobAutoControlSettings.JobEkMasks;
if (!trueEkStatuses.Any() || !trueMasks.Any())
{
logger.LogWarning($"В ApplicationInWork({applicationInWorkId}) не заданы настройки фильтрации статусов ЭК хоста или маски его имени");
return 0;
}
//Фильтруем обратное состояние - активированные для деактивации
query = FilterTemplatesQueryByWrongState(query, jobAutoControlSettings, isActivate);
//Фильтруем по маскам ЭК
var templates = FilterTemplatesByNameNotMatchToMasks(query, trueMasks);
if (!templates.Any())
return 0;
//Фильтруем по рабочим группам
var appInWorkWorkGroups = GetApplicationInWorkWorkGroups(applicationInWorkId);
if (appInWorkWorkGroups.Any())
templates = templates.Where(t => appInWorkWorkGroups.Any(awg => t.Host!.WorkGroupId == awg.WorkGroupId)).ToList();
//Фильтруем соответствие статусов ЭК условиям автоконтроля
var checkEkStatus = FilterTemplatesByWrongEkStatus(templates, trueEkStatuses, isActivate);
//Меняем состояние отфильтрованных шаблонов если какие-то остались
if (checkEkStatus.Any())
changes = UpdateState(checkEkStatus,
isActivate ? jobAutoControlSettings.OnTemplateIsActive : jobAutoControlSettings.OffTemplateIsActive,
isActivate ? jobAutoControlSettings.OnScheduleIsActive : jobAutoControlSettings.OffScheduleIsActive);
return changes;
}
private List<AppInWorkInWorkGroup> GetApplicationInWorkWorkGroups(Guid applicationInWorkId)
{
var appInWorkInWorkGroups = applicationsInWorkService.Get()
.Include(aiw => aiw.WorkGroups)
.FirstOrDefault(t => t.Id == applicationInWorkId)?.WorkGroups;
if (appInWorkInWorkGroups != null)
return appInWorkInWorkGroups.ToList();
return new List<AppInWorkInWorkGroup>();
}
private List<Template> FilterTemplatesByWrongEkStatus(List<Template> templates, ICollection<JobAutoControlInEkStatus> trueEkStatuses, bool isActivate)
{
if (isActivate)
return templates.Where(t => trueEkStatuses.Any(tes => tes.EkStatusCode == t.Host!.EkStatusCode)).ToList();
return templates.Where(t => !trueEkStatuses.Any(tes => tes.EkStatusCode == t.Host!.EkStatusCode)).ToList();
}
private List<Template> FilterTemplatesByNameNotMatchToMasks(IQueryable<Template> query, ICollection<JobEkMask> trueMasks)
{
var result = new List<Template>();
foreach (var mask in trueMasks)
{
var templates = query.Where(t => EF.Functions.Like(t.Host!.Ek.ToLower(), SqlHelpers.RegexToLike(mask.Name))).ToList();
result.AddRange(templates);
}
return result;
}
private IQueryable<Template> FilterTemplatesQueryByWrongState(IQueryable<Template> query, JobAutoControl jobAutoControlSettings, bool isActivate)
{
if (isActivate)
return query.Where(t => t.IsActiveTemplate != jobAutoControlSettings.OnTemplateIsActive || t.IsActiveSchedule != jobAutoControlSettings.OnScheduleIsActive);
return query.Where(t => t.IsActiveTemplate != jobAutoControlSettings.OffTemplateIsActive || t.IsActiveSchedule != jobAutoControlSettings.OffScheduleIsActive);
}
private async Task<JobAutoControl> GetJobAutoControlSettingsAsync(Guid applicationInWorkId)
{
return await jobAutoControlService.Get()
.Include(jac => jac.JobAutoControlInEkStatuses)
.Include(jac => jac.JobEkMasks)
.Where(jac => jac.ApplicationInWorkId == applicationInWorkId).FirstAsync();
}
/// <summary>
/// Обновить состояние расписаний по запросу query на newState, без записи в БД. Возвращает количество шаблонов требующих фиксации в БД
/// </summary>
/// <param name="query"></param>
/// <param name="newState"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Обновить состояние шаблонов по запросу query на newState, без записи в БД. Возвращает количество расписаний требующих фиксацию в БД
/// </summary>
/// <param name="query"></param>
/// <param name="newState"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Обновить состояние шаблонов по запросу query на newState, без записи в БД. Возвращает количество расписаний требующих фиксацию в БД
/// </summary>
/// <param name="query"></param>
/// <param name="newState"></param>
/// <returns></returns>
private async Task<int> UpdateStateAsync(IQueryable<Template> query, bool newTemplateState, bool newSchedulerState)
{
var templates = await query.Select(t => t).ToListAsync();
return UpdateState(templates, newTemplateState, newSchedulerState);
}
private int UpdateState(List<Template> templates, bool newTemplateState, bool newSchedulerState)
{
if (templates.Any())
templates.ForEach(t =>
{
t.IsActiveTemplate = newTemplateState;
t.IsActiveSchedule = newSchedulerState;
UpdateRobotConfiguration(RobotsEnum.TemplateOrder, t);
});
return templates.Count;
}
/// <summary>
/// принудительно обновить состояние задачи, связанной с шаблоном/расписанием, на обновление
/// </summary>
/// <param name="robotsEnum"></param>
/// <param name="t"></param>
private void UpdateRobotConfiguration(RobotsEnum robotsEnum, Template t)
{
var config = robotConfigurationService.GetFromTemplateByRobotCode(robotsEnum, ref t);
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, ref config);
}
}