2025-12-04 09:24:05 +10:00
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.Logging ;
2025-11-01 15:29:12 +10:00
using PARR.BLL.Domain.Mq ;
using PARR.BLL.Services.Interfaces ;
using PARR.Common.Domain ;
using PARR.Constants ;
using PARR.DAL.DomainServices.Interfaces ;
2025-12-04 09:24:05 +10:00
using PARR.DAL.Models ;
using PARR.DAL.Models.Job ;
using PARR.DAL.Services.Interfaces ;
using PARR.DAL.Services.Interfaces.Job ;
2025-11-01 15:29:12 +10:00
using PARR.TemplateMatcher.Settings ;
using System.Text.Json ;
namespace PARR.TemplateMatcher
{
2025-11-12 11:24:07 +10:00
internal class TemplateMatcher : ITemplateMatcher
2025-11-01 15:29:12 +10:00
{
2025-11-12 11:24:07 +10:00
private readonly ILogger < TemplateMatcher > logger ;
2025-11-01 15:29:12 +10:00
private readonly IUnitFilterService unitFilterService ;
private readonly MqSettings mqSettings ;
private readonly IMqService mqService ;
2025-12-04 09:24:05 +10:00
private readonly ITemplateService templateService ;
private readonly IJobService jobService ;
private readonly IShortcodesService shortcodesService ;
2025-11-01 15:29:12 +10:00
public TemplateMatcher (
2025-11-12 11:24:07 +10:00
ILogger < TemplateMatcher > logger ,
2025-11-01 15:29:12 +10:00
IUnitFilterService unitFilterService ,
MqSettings mqSettings ,
2025-12-04 09:24:05 +10:00
IMqService mqService ,
ITemplateService templateService ,
IJobService jobService ,
IShortcodesService shortcodesService
2025-11-01 15:29:12 +10:00
)
{
this . logger = logger ;
this . unitFilterService = unitFilterService ;
this . mqSettings = mqSettings ;
this . mqService = mqService ;
2025-12-04 09:24:05 +10:00
this . templateService = templateService ;
this . jobService = jobService ;
this . shortcodesService = shortcodesService ;
2025-11-01 15:29:12 +10:00
}
2025-12-04 09:24:05 +10:00
public async Task SyncTemplatesForJob ( Guid jobId , HistoryInitiator initiator )
2025-11-01 15:29:12 +10:00
{
2025-12-04 09:24:05 +10:00
logger . LogDebug ( "Начало синхронизации шаблонов для JobId {JobId}" , jobId ) ;
// 1. Получаем UnitId, которые должны иметь шаблоны (по фильтрам Job)
var units = await unitFilterService . GetUnitsIdByJobFilterAsync ( jobId ) ;
if ( units = = null )
{
logger . LogWarning ( "Для JobId {JobId} фильтр вернул null. Пропускаем." , jobId ) ;
return ;
}
var expectedUnitIds = units . ToHashSet ( ) ;
logger . LogDebug ( "Для JobId {JobId} найдено {Count} Unit'ов, соответствующих фильтрам." , jobId , expectedUnitIds . Count ) ;
if ( ! expectedUnitIds . Any ( ) )
{
logger . LogInformation ( "Для JobId {JobId} не найдено Unit'ов, соответствующих фильтрам." , jobId ) ;
return ;
}
// 2. Получаем все шаблоны для этого Job
var existingTemplates = await templateService . Get ( )
. Where ( t = > t . JobId = = jobId )
. ToListAsync ( ) ;
2025-11-01 15:29:12 +10:00
2025-12-04 09:24:05 +10:00
logger . LogDebug ( "Для JobId {JobId} найдено {Count} существующих шаблонов." , jobId , existingTemplates . Count ( ) ) ;
// 3. Получаем Job, чтобы получить маску имени
var job = await jobService . GetAsync ( jobId ) ;
if ( job = = null )
{
logger . LogError ( "Job с Id {JobId} не найден." , jobId ) ;
2025-11-01 15:29:12 +10:00
return ;
2025-12-04 09:24:05 +10:00
}
// 4. Находим UnitId, для которых нет шаблонов (нужно создать)
var existingUnitIds = existingTemplates . Select ( t = > t . UnitId ) . ToHashSet ( ) ;
var unitIdsToCreate = expectedUnitIds . Except ( existingUnitIds ) ;
2025-11-01 15:29:12 +10:00
2025-12-04 09:24:05 +10:00
logger . LogDebug ( "Для JobId {JobId} найдено {Count} Unit'ов без шаблонов (требуется создание)." , jobId , unitIdsToCreate . Count ( ) ) ;
foreach ( var unitId in unitIdsToCreate )
2025-11-01 15:29:12 +10:00
{
2025-12-04 09:24:05 +10:00
logger . LogInformation ( "Для UnitId {UnitId} нет шаблона, запрашиваем создание." , unitId ) ;
2025-11-01 15:29:12 +10:00
var mqRequest = new TemplateGeneratorWorkerMq
{
JobId = jobId ,
UnitId = unitId ,
2025-12-04 09:24:05 +10:00
HistoryInitiator = initiator
2025-11-01 15:29:12 +10:00
} ;
var msg = JsonSerializer . Serialize ( mqRequest ) ;
2025-11-20 14:24:03 +10:00
var result = await mqService . SendAsync ( mqSettings . TemplateGenerator , new [ ] { msg } ) ;
2025-11-01 15:29:12 +10:00
if ( result . IsSuccess )
2025-12-04 09:24:05 +10:00
logger . LogInformation ( "Отправлен запрос на создание шаблона для UnitId {UnitId} в JobId {JobId}" , unitId , jobId ) ;
2025-11-01 15:29:12 +10:00
else
2025-12-04 09:24:05 +10:00
logger . LogError ( "Ошибка при отправке запроса на создание шаблона для UnitId {UnitId} в JobId {JobId}: {Message}" , unitId , jobId , msg ) ;
2025-11-01 15:29:12 +10:00
}
2025-12-04 09:24:05 +10:00
// 5. Находим шаблоны, которые больше не соответствуют фильтрам (нужно отключить/обновить)
var unitIdsToRemove = existingUnitIds . Except ( expectedUnitIds ) ;
logger . LogDebug ( "Для JobId {JobId} найдено {Count} Unit'ов с шаблонами, которые больше не соответствуют фильтрам (требуется обновление/отключение)." , jobId , unitIdsToRemove . Count ( ) ) ;
foreach ( var template in existingTemplates )
{
var unitId = template . UnitId ;
if ( unitIdsToRemove . Contains ( template . UnitId ) )
{
logger . LogInformation ( "Шаблон {TemplateId} для UnitId {UnitId} больше не соответствует фильтрам Job. Требуется обновление статуса." , template . Id , template . UnitId ) ;
// 1. Меняем статус
template . StatusTypeId = TemplateStatusTypeEnum . Updating ;
// 2. Сохраняем изменения в базе через сервис
var saved = await templateService . CommitAsync ( initiator ) ;
if ( ! saved )
{
logger . LogError ( null , "Н е удалось сохранить изменения шаблона {TemplateId} перед отправкой в очередь обновления." , template . Id ) ;
continue ; // пропускаем этот шаблон
}
// 3. Подготовим сообщение
var updateRequest = new TemplateUpdaterMq
{
TemplateId = template . Id ,
JobId = template . JobId ,
Name = await shortcodesService . ApplyShortcodesAsync ( job . TemplateNameMask , template . UnitId , jobId ) ,
IsActiveTemplate = template . IsActiveTemplate ,
IsActiveSchedule = false ,
LastRun = template . LastRun ,
NextRun = template . NextRun ,
UnitId = template . UnitId ,
Index = template . Index ,
StatusTypeId = TemplateStatusTypeEnum . Unused , // после обновления статус должен быть Unused
Initiator = initiator
} ;
// 4. Отправляем в очередь
await SendTemplateUpdateMessage ( updateRequest ) ;
}
else
{
// Unit всё ещё соответствует фильтрам — проверим, нужно ли обновить имя
logger . LogDebug ( "Шаблон {TemplateId} для UnitId {UnitId} соответствует фильтрам. Проверяем имя." , template . Id , unitId ) ;
await CheckAndSendNameUpdateIfRequired ( template , job , initiator ) ;
}
}
logger . LogDebug ( "Окончание синхронизации шаблонов для JobId {JobId}" , jobId ) ;
2025-11-01 15:29:12 +10:00
}
2025-12-04 09:24:05 +10:00
public async Task UpdateTemplatesForJob ( Guid jobId , HistoryInitiator initiator )
2025-11-01 15:29:12 +10:00
{
2025-12-04 09:24:05 +10:00
logger . LogDebug ( "Начало обновления имён шаблонов для JobId {JobId}" , jobId ) ;
// 1. Получаем все шаблоны для этого Job
var existingTemplates = await templateService . Get ( )
. Where ( t = > t . JobId = = jobId )
. ToListAsync ( ) ;
logger . LogDebug ( "Для JobId {JobId} найдено {Count} существующих шаблонов." , jobId , existingTemplates . Count ( ) ) ;
if ( ! existingTemplates . Any ( ) )
{
logger . LogInformation ( "Для JobId {JobId} не найдено существующих шаблонов для обновления имени." , jobId ) ;
return ;
}
// 2. Получаем Job, чтобы получить маску имени
var job = await jobService . GetAsync ( jobId ) ;
if ( job = = null )
{
logger . LogError ( "Job с Id {JobId} не найден." , jobId ) ;
return ;
}
foreach ( var template in existingTemplates )
{
logger . LogDebug ( "Проверяем имя шаблона {TemplateId} для UnitId {UnitId}." , template . Id , template . UnitId ) ;
// Проверяем, нужно ли обновить имя
await CheckAndSendNameUpdateIfRequired ( template , job , initiator ) ;
}
logger . LogDebug ( "Окончание обновления имён шаблонов для JobId {JobId}" , jobId ) ;
2025-11-01 15:29:12 +10:00
}
2025-12-04 09:24:05 +10:00
private async Task CheckAndSendNameUpdateIfRequired ( Template template , Job job , HistoryInitiator initiator )
2025-11-01 15:29:12 +10:00
{
2025-12-04 09:24:05 +10:00
var expectedName = await shortcodesService . ApplyShortcodesAsync ( job . TemplateNameMask , template . UnitId , job . Id ) ;
logger . LogDebug ( "Шаблон {TemplateId}: текущее имя '{CurrentName}', ожидаемое имя '{ExpectedName}'" , template . Id , template . Name , expectedName ) ;
if ( template . Name ! = expectedName )
{
logger . LogInformation ( "Шаблон {TemplateId} для UnitId {UnitId} имеет устаревшее имя. Требуется обновление." , template . Id , template . UnitId ) ;
// 1. Меняем статус в шаблоне
template . StatusTypeId = TemplateStatusTypeEnum . Updating ;
// 2. Сохраняем изменения в базе через сервис
var saved = await templateService . CommitAsync ( initiator ) ;
if ( ! saved )
{
logger . LogError ( "Н е удалось сохранить изменения шаблона {TemplateId} перед отправкой в очередь обновления." , template . Id ) ;
return ; // не отправляем сообщение, если не сохранили
}
// 3. Подготовим сообщение для отправки в очередь
var updateRequest = new TemplateUpdaterMq
{
TemplateId = template . Id ,
JobId = template . JobId ,
Name = expectedName ,
IsActiveTemplate = template . IsActiveTemplate ,
IsActiveSchedule = template . IsActiveSchedule ,
LastRun = template . LastRun ,
NextRun = template . NextRun ,
UnitId = template . UnitId ,
Index = template . Index ,
StatusTypeId = TemplateStatusTypeEnum . Used ,
Initiator = initiator
} ;
// 4. Отправляем в очередь
await SendTemplateUpdateMessage ( updateRequest ) ;
}
else
{
logger . LogDebug ( "Шаблон {TemplateId} для UnitId {UnitId} имеет актуальное имя." , template . Id , template . UnitId ) ;
}
2025-11-01 15:29:12 +10:00
}
2025-12-04 09:24:05 +10:00
private async Task SendTemplateUpdateMessage ( TemplateUpdaterMq updateRequest )
{
logger . LogDebug ( "Отправка сообщения в очередь '{Queue}' для шаблона {TemplateId}" ,
mqSettings . TemplateUpdater . QueueName , updateRequest . TemplateId ) ;
var msg = JsonSerializer . Serialize ( updateRequest ) ;
2025-11-01 15:29:12 +10:00
2025-12-04 09:24:05 +10:00
var result = await mqService . SendAsync ( mqSettings . TemplateUpdater , new [ ] { msg } ) ;
if ( result . IsSuccess )
{
logger . LogInformation ( "Отправлен запрос на обновление шаблона {TemplateId}" , updateRequest . TemplateId ) ;
}
else
{
logger . LogError ( "Ошибка при отправке запроса на обновление шаблона {TemplateId}: {Message}" ,
updateRequest . TemplateId , msg ) ;
}
}
2025-11-01 15:29:12 +10:00
}
2025-12-04 09:24:05 +10:00
}