Files
parr_api/PARR.TemplateUpdater/Services/TemplateUpdaterService.cs

254 lines
11 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.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.Extensions;
using PARR.DAL.Models;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Unit;
namespace PARR.TemplateUpdater.Services
{
internal class TemplateUpdaterService : ITemplateUpdaterService
{
private readonly ILogger<TemplateUpdaterService> logger;
private readonly ITemplateService templateService;
private readonly IJobService jobService;
private readonly IUnitService unitService;
private readonly IRobotConfigurationService robotConfigurationService;
private readonly INextRunService nextRunService;
public TemplateUpdaterService(
ILogger<TemplateUpdaterService> logger,
ITemplateService templateService,
IJobService jobService,
IUnitService unitService,
IRobotConfigurationService robotConfigurationService,
INextRunService nextRunService
)
{
this.logger = logger;
this.templateService = templateService;
this.jobService = jobService;
this.unitService = unitService;
this.robotConfigurationService = robotConfigurationService;
this.nextRunService = nextRunService;
}
public async Task UpdateTemplateAsync(TemplateUpdaterMq query)
{
var isValid = await IsValidAsync(query);
if (!isValid)
{
logger.LogError("Не валидны входные данные. Конец обработки сообщения {Query}", query.ToJson());
return;
}
var template = await templateService.Get()
.Include(t => t.RobotConfigurations)
.Include(t => t.UnitsInTemplate)
.AsSplitQuery()
.FirstOrDefaultAsync(t => t.Id == query.TemplateId);
if (template == null)
{
logger.LogError("Не найден шаблон с id {TemplateId}", query.TemplateId);
return;
}
var templateIsChanged = false;
var scheduleIsChanged = false;
if (template.Name != query.Name.Trim())
{
template.Name = query.Name.Trim();
templateIsChanged = true;
scheduleIsChanged = true;
}
if (template.JobId != query.JobId)
{
template.JobId = query.JobId;
templateIsChanged = true;
scheduleIsChanged = true;
}
if (template.IsActiveTemplate != query.IsActiveTemplate)
{
template.IsActiveTemplate = query.IsActiveTemplate;
templateIsChanged = true;
}
if (template.IsActiveSchedule != query.IsActiveSchedule)
{
template.IsActiveSchedule = query.IsActiveSchedule;
scheduleIsChanged = true;
}
var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, query.IsNew);
if (!nextRun.HasValue)
{
logger.LogError("Ошибка при расчете нового nextRun (вернулся null) для шаблона {templateId}, {templateName}", template.Id, template.Name);
return;
}
//if (template.NextRun != query.NextRun)
//{
// template.NextRun = query.NextRun;
// scheduleIsChanged = true;
//}
if (template.NextRun != nextRun.Value)
{
template.LastRun = template.NextRun;
template.NextRun = nextRun.Value;
scheduleIsChanged = true;
}
if (template.UnitId != query.UnitId)
{
template.UnitId = query.UnitId;
templateIsChanged = true;
scheduleIsChanged = true;
}
//просто обнволяем. не влияет ни на шаблон, ни на расписание
//template.LastRun = query.LastRun;
template.Index = query.Index;
template.StatusTypeId = query.StatusTypeId;
// === Обработка изменения состава UnitsInTemplate ===
var currentUnitIds = template.UnitsInTemplate.Select(u => u.UnitId).ToHashSet();
var newUnitIds = query.UnitsInTemplate.ToHashSet();
if (!currentUnitIds.SetEquals(newUnitIds))
{
// Удаляем старые связи
var toRemove = template.UnitsInTemplate
.Where(u => !newUnitIds.Contains(u.UnitId))
.ToList();
foreach (var item in toRemove)
template.UnitsInTemplate.Remove(item);
// Добавляем новые связи
var toAdd = newUnitIds.Except(currentUnitIds);
foreach (var unitId in toAdd)
{
template.UnitsInTemplate.Add(new UnitsInTemplate
{
TemplateId = template.Id,
UnitId = unitId,
DateCreated = DateTimeOffset.UtcNow
});
}
// Поскольку коллекция изменилась — шаблон считается изменённым
templateIsChanged = true;
}
// === конец обработки UnitsInTemplate ===
if (templateIsChanged)
{
// ставим задачу на обновление шаблона
var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.TemplateOrder, template);
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, config);
logger.LogDebug("Для шаблона {TemplateId} устанавливаю статус {Status}", template.Id, RobotStatusEnum.Wait.ToString());
}
if (scheduleIsChanged)
{
// ставим задачу на обновление расписания
var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, template);
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, config);
logger.LogDebug("Для расписания {TemplateId} устанавливаю статус {Status}", template.Id, RobotStatusEnum.Wait.ToString());
}
if (!await templateService.CommitAsync(query.Initiator))
{
logger.LogError("Не удалось сохранить изменения в БД. {QueryType}: {Query}", nameof(TemplateUpdaterMq), query.ToJson());
return;
}
logger.LogInformation("Выполнено изменение шаблона в БД. Отправлен запрос на синхронизацию шаблона: {TemplateIsChanged}, расписания: {ScheduleIsChanged}. Query {Query}", templateIsChanged, scheduleIsChanged, query.ToJson());
}
/// <summary>
/// Валидация входящего сообщения
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
private async Task<bool> IsValidAsync(TemplateUpdaterMq query)
{
var template = await templateService.Get().AsNoTracking()
.Include(t => t.RobotConfigurations)
.FirstOrDefaultAsync(t => t.Id == query.TemplateId);
if (template == null)
{
logger.LogError("Сообщение не валидно. Не найден шаблон с id: {TemplateId}", query.TemplateId);
return false;
}
if (template.ScheduleEsppId == null)
{
logger.LogError("Сообщение не валидно. Номер расписания не может быть null, робот не сможет обновить шаблон: {TemplateName}", template.Name);
return false;
}
var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.TemplateOrder, template);
if (config == null)
{
logger.LogError("Сообщение не валидно. Не создана конфигурация роботов: {TemplateName}", template.Name);
return false;
}
if (config.TaskStatusCode != (int)TaskStatusEnum.Ok)
{
logger.LogError("Сообщение не валидно. Не закончено создание или предыдущее обновление - нельзя начинать новое изменение шаблона: {TemplateName}", template.Name);
return false;
}
if (string.IsNullOrEmpty(query.Name?.Trim()))
{
logger.LogError("Сообщение не валидно. Имя шаблона не может быть пустым: {TemplateName}", query.Name);
return false;
}
var existTemplateName = await templateService.Get().AsNoTracking().AnyAsync(t =>
t.Id != query.TemplateId
&& t.Name!.ToUpper() == query.Name.Trim().ToUpper()
&& t.Index == query.Index);
if (existTemplateName)
{
logger.LogError("Сообщение не валидно. Имя шаблона не уникально: {TemplateName}", query.Name);
return false;
}
var job = await jobService.Get().AsNoTracking().AnyAsync(t => t.Id == query.JobId);
if (!job)
{
logger.LogError("Сообщение не валидно. Не найдена работа с JobId: {JobId}", query.JobId);
return false;
}
var unit = await unitService.Get().AsNoTracking().AnyAsync(t => t.Id == query.UnitId);
if (!unit)
{
logger.LogError("Сообщение не валидно. Не найден unit с UnitId: {UnitId}", query.UnitId);
return false;
}
return true;
}
}
}