@@ -1,7 +1,6 @@
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.Logging ;
using Microsoft.Extensions.Options ;
using PARR.Core.Common.Interfaces.RabbitServices ;
using PARR.Core.Repositories.Interfaces ;
using PARR.Core.Repositories.Interfaces.JobRepositories ;
using PARR.Core.Repositories.Interfaces.Unit ;
@@ -26,41 +25,32 @@ namespace PARR.TemplateMatcher.Services.Implementations;
internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
{
#if DEBUG
private readonly Guid targetUnitId = Guid . Parse ( "358437ac-1eeb-4c00-840c-998326f657ac" ) ;
private readonly Guid _ targetUnitId = Guid . Parse ( "358437ac-1eeb-4c00-840c-998326f657ac" ) ;
#endif
private const bool DefaultUsedTemplate Stat e = false ;
private const bool DefaultUsedSchedul eStat e = false ;
private readonly IEnumerable < ISimpleSyncStage > readStages ;
private readonly IEnumerable < ISimpleSyncWriteStage > writeStages ;
private readonly ILogger < SimpleTemplateSynchronizer > logger ;
private readonly IUnitFilterService unitFilterService ;
private readonly MqSettings mqSettings ;
private readonly IRabbitService mq Service ;
private readonly ITemplateRepository templateService ;
private readonly IJobRepository jobService ;
private readonly ITemplateNameNormalizer templateNameNormalizer ;
private readonly ITemplateAllocationService templateAllocation Service ;
private readonly ITemplateMqPublisher templateMqPublisher ;
private readonly IMatchingStatusService matchingStatusService ;
private readonly SettingsFromDb settingsFromDb ;
private readonly IOptions < TemplateSettings > templateSettings ;
private readonly IUnitFieldRepository unitFieldService ;
private readonly IUnitInValueRepository unitInValueService ;
private readonly IUnitRepository unitRepository ;
private readonly IEnumerable < ISimpleSync Stag e> _readStages ;
private readonly IEnumerable < ISimpleSyncWrit eStag e> _writeStages ;
private readonly ILogger < SimpleTemplateSynchronizer > _logger ;
private readonly IUnitFilterService _unitFilterService ;
private readonly ITemplateRepository _templateService ;
private readonly IJobRepository _jobService ;
private readonly ITemplateNameNormalizer _templateNameNormalizer ;
private readonly ITemplateMqPublisher _templateMqPublisher ;
private readonly IMatchingStatusService _matchingStatus Service ;
private readonly SettingsFromDb _settingsFromDb ;
private readonly IOptions < TemplateSettings > _templateSettings ;
private readonly IUnitFieldRepository _unitFieldService ;
private readonly IUnitInValueRepository _unitInValue Service ;
private readonly IUnitRepository _unitRepository ;
public SimpleTemplateSynchronizer (
IEnumerable < ISimpleSyncStage > readStages ,
IEnumerable < ISimpleSyncWriteStage > writeStages ,
ILogger < SimpleTemplateSynchronizer > logger ,
IUnitFilterService unitFilterService ,
MqSettings mqSettings ,
IRabbitService mqService ,
ITemplateRepository templateService ,
IJobRepository jobService ,
ITemplateNameNormalizer templateNameNormalizer ,
ITemplateAllocationService templateAllocationService ,
ITemplateMqPublisher templateMqPublisher ,
IMatchingStatusService matchingStatusService ,
SettingsFromDb settingsFromDb ,
@@ -70,40 +60,37 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
IUnitRepository unitRepository
)
{
this . readStages = readStages ;
this . writeStages = writeStages ;
this . logger = logger ;
this . unitFilterService = unitFilterService ;
this . mqSettings = mqSettings ;
this . mq Service = mq Service;
this . templateService = templateService ;
this . jobService = jobService ;
this . templateNameNormalizer = templateNameNormalizer ;
this . templateAllocationService = templateAllocationService ;
this . templateMqPublisher = templateMqPublisher ;
this . matchingStatusService = matchingStatus Service;
this . settingsFromDb = settingsFromDb ;
this . templateSettings = templateSettings ;
this . unitFieldService = unitFieldService ;
this . unitInValueService = unitInValueService ;
this . unitRepository = unitRepository ;
this . _ readStages = readStages ;
this . _ writeStages = writeStages ;
this . _ logger = logger ;
this . _ unitFilterService = unitFilterService ;
this . _templateService = templateService ;
this . _job Service = job Service;
this . _ templateNameNormalizer = templateNameNormalizer ;
this . _templateMqPublisher = templateMqPublisher ;
this . _matchingStatusService = matchingStatusService ;
this . _settingsFromDb = settingsFromDb ;
this . _ templateSettings = templateSettings ;
this . _unitFieldService = unitField Service;
this . _unitInValueService = unitInValueService ;
this . _unitRepository = unitRepository ;
}
public async Task SyncTemplatesForJobAsync ( Guid jobId , HistoryInitiator initiator )
{
if ( jobId = = settingsFromDb . JobIdForUnusedTemplates )
if ( jobId = = _ settingsFromDb. JobIdForUnusedTemplates )
{
logger . LogInformation ( "Обработка синхронизации для Job неиспользуемых шаблонов '{JobId}'" , jobId ) ;
_ logger. LogInformation ( "Обработка синхронизации для Job неиспользуемых шаблонов '{JobId}'" , jobId ) ;
await SyncUnusedTemplatesAsync ( jobId , initiator ) ;
return ;
}
logger . LogInformation ( "Начало синхронизации шаблонов для Job {JobId}" , jobId ) ;
_ logger. LogInformation ( "Начало синхронизации шаблонов для Job {JobId}" , jobId ) ;
var existingStatus = await matchingStatusService . GetStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
if ( existingStatus . DetailsJobs ? . Any ( ) = = true )
var existingStatus = await _ matchingStatusService. GetStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
if ( existingStatus . DetailsJobs ? . Count > 0 )
{
logger . LogWarning ( "Синхронизация для Job {JobId} уже запущена. Пропускаем." , jobId ) ;
_ logger. LogWarning ( "Синхронизация для Job {JobId} уже запущена. Пропускаем." , jobId ) ;
return ;
}
@@ -113,49 +100,48 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
Action = TemplateMatcherActionEnum . Sync ,
Comment = "Начало синхронизации"
} ;
await matchingStatusService . SetMatchingStatusAsync (
await _ matchingStatusService. SetMatchingStatusAsync (
jobId , SyncTaskEntityTypeEnum . Job ,
new MatchingStatusItem { Data = initialStatus , Timestamp = DateTimeOffset . UtcNow , Source = nameof ( SimpleTemplateSynchronizer ) } ,
TimeSpan . FromMinutes ( 35 ) ) ;
// Таймер запускается ПОСЛЕ инфраструктурных операций (статус, проверка блокировки)
var totalSw = Stopwatch . StartNew ( ) ;
var context = new SimpleSyncContext { JobId = jobId , Initiator = initiator } ;
try
{
var context = new SimpleSyncContext { JobId = jobId , Initiator = initiator } ;
foreach ( var stage in readStages )
foreach ( var stage in _readStages )
{
var stageSw = Stopwatch . StartNew ( ) ;
await stage . ExecuteAsync ( context ) ;
stageSw . Stop ( ) ;
logger . LogDebug ( "[Perf] Job '{JobName}' ({JobId}) | Этап: {Stage} | Время: {Ms} мс" ,
_ logger. LogDebug ( "[Perf] Job '{JobName}' ({JobId}) | Этап: {Stage} | Время: {Ms} мс" ,
context . JobName , jobId , stage . StageName , stageSw . ElapsedMilliseconds ) ;
}
foreach ( var stage in writeStages )
foreach ( var stage in _ writeStages)
{
var stageSw = Stopwatch . StartNew ( ) ;
await stage . ExecuteAsync ( context ) ;
stageSw . Stop ( ) ;
logger . LogDebug ( "[Perf] Job '{JobName}' ({JobId}) | Этап: {Stage} | Время: {Ms} мс" ,
_ logger. LogDebug ( "[Perf] Job '{JobName}' ({JobId}) | Этап: {Stage} | Время: {Ms} мс" ,
context . JobName , jobId , stage . StageName , stageSw . ElapsedMilliseconds ) ;
}
totalSw . Stop ( ) ;
logger . LogInformation ( "[Perf] Job '{JobName}' ({JobId}) | ИТОГО: {TotalMs} мс" ,
_ logger. LogInformation ( "[Perf] Job '{JobName}' ({JobId}) | ИТОГО: {TotalMs} мс" ,
context . JobName , jobId , totalSw . ElapsedMilliseconds ) ;
await UpdateMatchingStatusAsync ( jobId , "Синхронизация завершена успешно" ) ;
await matchingStatusService . DeleteMatchingStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
logger . LogInformation ( "Синхронизация шаблонов завершена для Job '{JobName}' ({JobId})" ,
await _ matchingStatusService. DeleteMatchingStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
_ logger. LogInformation ( "Синхронизация шаблонов завершена для Job '{JobName}' ({JobId})" ,
context . JobName , jobId ) ;
}
catch ( Exception ex )
{
totalSw . Stop ( ) ;
logger . LogError ( ex , "Ошибка при синхронизации Job '{JobName}' ({JobId}) через {ElapsedMs} мс" ,
_ logger. LogError ( ex , "Ошибка при синхронизации Job '{JobName}' ({JobId}) через {ElapsedMs} мс" ,
string . Empty , jobId , totalSw . ElapsedMilliseconds ) ;
await UpdateMatchingStatusAsync ( jobId , $"Ошибка: {ex.Message}" ) ;
throw ;
@@ -165,19 +151,19 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
public async Task SyncTemplatesForJobGroupAsync ( Guid jobGroupId , HistoryInitiator initiator )
{
logger . LogWarning ( "SimpleTemplateSynchronizer: SyncTemplatesForJobGroup вызван для JobGroup {JobGroupId}. Это не поддерживаемая операция." , jobGroupId ) ;
_ logger. LogWarning ( "SimpleTemplateSynchronizer: SyncTemplatesForJobGroup вызван для JobGroup {JobGroupId}. Это не поддерживаемая операция." , jobGroupId ) ;
}
public async Task UpdateTemplatesForJobAsync ( Guid jobId , HistoryInitiator initiator )
{
logger . LogDebug ( "Обновление шаблонов для Job {JobId}" , jobId ) ;
_ logger. LogDebug ( "Обновление шаблонов для Job {JobId}" , jobId ) ;
// === Проверка: уже запущена? ===
var existingStatus = await matchingStatusService . GetStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
if ( existingStatus . DetailsJobs ? . Any ( ) = = true )
var existingStatus = await _ matchingStatusService. GetStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
if ( existingStatus . DetailsJobs ? . Count > 0 )
{
logger . LogWarning ( "Обновление для Job {JobId} уже запущено. Пропускаем." , jobId ) ;
_ logger. LogWarning ( "Обновление для Job {JobId} уже запущено. Пропускаем." , jobId ) ;
return ;
}
@@ -187,7 +173,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
Action = TemplateMatcherActionEnum . Update ,
Comment = "Начало обновления имён"
} ;
await matchingStatusService . SetMatchingStatusAsync (
await _ matchingStatusService. SetMatchingStatusAsync (
jobId ,
SyncTaskEntityTypeEnum . Job ,
new MatchingStatusItem { Data = initialStatus , Timestamp = DateTimeOffset . UtcNow , Source = nameof ( SimpleTemplateSynchronizer ) } ,
@@ -196,7 +182,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
try
{
var job = await jobService . Get ( )
var job = await _ jobService. Get ( )
. AsNoTracking ( )
. Include ( j = > j . AutoControl )
. Include ( j = > j . Tnk )
@@ -208,18 +194,18 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
if ( job = = null )
{
logger . LogWarning ( "Job {JobId} не найден." , jobId ) ;
_ logger. LogWarning ( "Job {JobId} не найден." , jobId ) ;
await UpdateMatchingStatusAsync ( jobId , "Job не найден" ) ;
return ;
}
// === Получение отфильтрованных юнитов с полной информацией ===
var filteredUnits = await unitFilterService . GetUnitsByJobFilterAsync ( jobId ) ;
var filteredUnits = await _ unitFilterService. GetUnitsByJobFilterAsync ( jobId ) ;
if ( filteredUnits = = null | | ! filteredUnits . Any ( ) )
{
logger . LogInformation ( "Для Job {JobId} фильтры не дали Unit'ов." , jobId ) ;
_ logger. LogInformation ( "Для Job {JobId} фильтры не дали Unit'ов." , jobId ) ;
await UpdateMatchingStatusAsync ( jobId , "Нет Unit'ов — обновление не требуется" ) ;
await matchingStatusService . DeleteMatchingStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
await _ matchingStatusService. DeleteMatchingStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
return ;
}
@@ -228,17 +214,17 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
#if DEBUG
// Отладка: проверить, есть ли юнит в unitIds
if ( unitIds . Contains ( targetUnitId ) )
if ( unitIds . Contains ( _ targetUnitId) )
{
logger . LogDebug ( "Юнит {TargetUnitId} найден в unitIds." , targetUnitId ) ;
_ logger. LogDebug ( "Юнит {TargetUnitId} найден в unitIds." , _ targetUnitId) ;
}
else
{
logger . LogDebug ( "Юнит {TargetUnitId} Н Е найден в unitIds." , targetUnitId ) ;
_ logger. LogDebug ( "Юнит {TargetUnitId} Н Е найден в unitIds." , _ targetUnitId) ;
}
#endif
var existingTemplates = await templateService . Get ( )
var existingTemplates = await _ templateService. Get ( )
. AsNoTracking ( )
. Include ( t = > t . Unit )
. Include ( t = > t . UnitsInTemplate )
@@ -254,10 +240,10 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
{
if ( unitIds . Contains ( template . UnitId ) )
{
var expectedName = await templateNameNormalizer . GetNormalizedTemplateNameAsync ( template ) ;
var expectedName = await _ templateNameNormalizer. GetNormalizedTemplateNameAsync ( template ) ;
if ( ! string . Equals ( template . Name , expectedName , StringComparison . OrdinalIgnoreCase ) )
{
logger . LogDebug ( "Шаблон {TemplateId} требует обновления имени: старое = '{OldName}', новое = '{NewName}'" , template . Id , template . Name , expectedName ) ;
_ logger. LogDebug ( "Шаблон {TemplateId} требует обновления имени: старое = '{OldName}', новое = '{NewName}'" , template . Id , template . Name , expectedName ) ;
var updateRequest = new TemplateUpdaterMessage
{
@@ -274,18 +260,18 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
UnitsInTemplate = new List < UnitInTemplateMessage > ( ) // для простого шаблона
} ;
await templateMqPublisher . PublishUpdateAsync ( updateRequest ) ;
await _ templateMqPublisher. PublishUpdateAsync ( updateRequest ) ;
}
}
}
await UpdateMatchingStatusAsync ( jobId , "Обновление завершено" ) ;
await matchingStatusService . DeleteMatchingStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
logger . LogInformation ( "Обновление шаблонов завершено для Job {JobId}." , jobId ) ;
await _ matchingStatusService. DeleteMatchingStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
_ logger. LogInformation ( "Обновление шаблонов завершено для Job {JobId}." , jobId ) ;
}
catch ( Exception ex )
{
logger . LogError ( ex , "Ошибка при обновлении Job {JobId}" , jobId ) ;
_ logger. LogError ( ex , "Ошибка при обновлении Job {JobId}" , jobId ) ;
await UpdateMatchingStatusAsync ( jobId , $"Ошибка: {ex.Message}" ) ;
throw ;
}
@@ -297,10 +283,10 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
// Проверка отмены в самом начале
ct . ThrowIfCancellationRequested ( ) ;
var existingStatus = await matchingStatusService . GetStatusAsync ( unusedJobId , SyncTaskEntityTypeEnum . Job ) ;
if ( existingStatus . DetailsJobs ? . Any ( ) = = true )
var existingStatus = await _ matchingStatusService. GetStatusAsync ( unusedJobId , SyncTaskEntityTypeEnum . Job ) ;
if ( existingStatus . DetailsJobs ? . Count > 0 )
{
logger . LogWarning ( "Синхронизация для Job неиспользуемых шаблонов {JobId} уже запущена. Пропускаем." , unusedJobId ) ;
_ logger. LogWarning ( "Синхронизация для Job неиспользуемых шаблонов {JobId} уже запущена. Пропускаем." , unusedJobId ) ;
return ;
}
@@ -310,22 +296,24 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
Action = TemplateMatcherActionEnum . Sync ,
Comment = "Синхронизация неиспользуемых шаблонов"
} ;
await matchingStatusService . SetMatchingStatusAsync (
await _ matchingStatusService. SetMatchingStatusAsync (
unusedJobId ,
SyncTaskEntityTypeEnum . Job ,
new MatchingStatusItem { Data = initialStatus , Timestamp = DateTimeOffset . UtcNow , Source = nameof ( SimpleTemplateSynchronizer ) } ,
TimeSpan . FromMinutes ( 30 )
) ;
var totalSw = Stopwatch . StartNew ( ) ;
try
{
// 1. Находим ID нужных полей
var responsableAreaField = await unitFieldService . GetByAihitNameAsync ( UnusedTemplateConstants . ResponsibilityAreaFieldName ) ;
var tagField = await unitFieldService . GetByAihitNameAsync ( UnusedTemplateConstants . ParrTagFieldName ) ;
var responsableAreaField = await _ unitFieldService. GetByAihitNameAsync ( UnusedTemplateConstants . ResponsibilityAreaFieldName , ct );
var tagField = await _ unitFieldService. GetByAihitNameAsync ( UnusedTemplateConstants . ParrTagFieldName , ct );
if ( responsableAreaField = = null | | tagField = = null )
{
logger . LogError ( "Н е найдены поля '{Field1}' или '{Field2}'. Синхронизация прервана." , UnusedTemplateConstants . ResponsibilityAreaFieldName , UnusedTemplateConstants . NotUsedTagValue ) ;
_ logger. LogError ( "Н е найдены поля '{Field1}' или '{Field2}'. Синхронизация прервана." , UnusedTemplateConstants . ResponsibilityAreaFieldName , UnusedTemplateConstants . NotUsedTagValue ) ;
await UpdateMatchingStatusAsync ( unusedJobId , "Ошибка конфигурации полей" ) ;
return ;
}
@@ -334,7 +322,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
var tagFieldId = tagField . Id ;
// 2. Находим ValueId для тега "ПАРР-НЕИСП"
var targetTagValueId = await unitInValueService . Get ( )
var targetTagValueId = await _ unitInValueService. Get ( )
. AsNoTracking ( )
. Where ( uiv = > uiv . FieldId = = tagFieldId & & uiv . Value ! = null & & uiv . Value . Value = = UnusedTemplateConstants . NotUsedTagValue )
. Select ( uiv = > uiv . ValueId )
@@ -342,31 +330,31 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
if ( targetTagValueId = = Guid . Empty )
{
logger . LogWarning ( "Значение '{TagValue}' для поля '{FieldName}' не найдено в справочнике UnitFieldValue." , UnusedTemplateConstants . NotUsedTagValue , UnusedTemplateConstants . ParrTagFieldName ) ;
_ logger. LogWarning ( "Значение '{TagValue}' для поля '{FieldName}' не найдено в справочнике UnitFieldValue." , UnusedTemplateConstants . NotUsedTagValue , UnusedTemplateConstants . ParrTagFieldName ) ;
}
var unusedJob = await jobService . Get ( ) . AsNoTracking ( )
var unusedJob = await _ jobService. Get ( ) . AsNoTracking ( )
. Include ( t = > t ! . Group ) . ThenInclude ( t = > t ! . GroupType )
. Include ( t = > t ! . Tnk )
. FirstOrDefaultAsync ( j = > j . Id = = unusedJobId , ct ) ;
if ( unusedJob = = null )
{
logger . LogError ( "Job неиспользуемых шаблонов {JobId} не найден." , unusedJobId ) ;
_ logger. LogError ( "Job неиспользуемых шаблонов {JobId} не найден." , unusedJobId ) ;
await UpdateMatchingStatusAsync ( unusedJobId , "Job не найден" ) ;
return ;
}
var unusedTemplates = await templateService . Get ( )
var unusedTemplates = await _ templateService. Get ( )
. Include ( t = > t . Unit )
. Where ( t = > t . StatusTypeId = = TemplateStatusTypeEnum . Unused )
. ToListAsync ( ct ) ;
if ( ! unusedTemplates . Any ( ) )
{
logger . LogInformation ( "Н е найдено шаблонов с о статусом Unused." ) ;
_ logger. LogInformation ( "Н е найдено шаблонов с о статусом Unused." ) ;
await UpdateMatchingStatusAsync ( unusedJobId , "Нет шаблонов для обработки" ) ;
await matchingStatusService . DeleteMatchingStatusAsync ( unusedJobId , SyncTaskEntityTypeEnum . Job ) ;
await _ matchingStatusService. DeleteMatchingStatusAsync ( unusedJobId , SyncTaskEntityTypeEnum . Job ) ;
return ;
}
@@ -376,7 +364,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
var allTemplateUnitIds = unusedTemplates . Select ( t = > t . UnitId ) . Distinct ( ) . ToList ( ) ;
// Получаем значения З О Н А _О Т В Е Т С Т В Е Н Н О С Т И для всех юнитов шаблонов
var unitResponsableAreaValues = await unitInValueService . GetByUnitIdsAndFieldIdsAsync ( allTemplateUnitIds , new List < Guid > { responsableAreaFieldId } ) ;
var unitResponsableAreaValues = await _ unitInValueService. GetByUnitIdsAndFieldIdsAsync ( allTemplateUnitIds , new List < Guid > { responsableAreaFieldId } , ct );
var unitToResponsableAreaValueMap = unitResponsableAreaValues
. Where ( uiv = > uiv . ValueId ! = Guid . Empty )
. ToDictionary ( uiv = > uiv . UnitId , uiv = > uiv . ValueId ) ;
@@ -385,15 +373,16 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
var responsableAreaToTargetUnitMap = new Dictionary < Guid , Guid > ( ) ;
var distinctResponsableAreaValues = unitToResponsableAreaValueMap . Values . Distinct ( ) . ToList ( ) ;
if ( targetTagValueId ! = Guid . Empty & & distinctResponsableAreaValues . Any ( ) )
if ( targetTagValueId ! = Guid . Empty & &
distinctResponsableAreaValues . Any ( ) )
{
logger . LogDebug ( "Пакетный поиск целевых юнитов с тегом 'ПАРР-НЕИСП' для {Count} уникальных значений З О Н А _О Т В Е Т С Т В Е Н Н О С Т И." , distinctResponsableAreaValues . Count ) ;
_ logger. LogDebug ( "Пакетный поиск целевых юнитов с тегом 'ПАРР-НЕИСП' для {Count} уникальных значений З О Н А _О Т В Е Т С Т В Е Н Н О С Т И." , distinctResponsableAreaValues . Count ) ;
// Передаем ct в ToListAsync
var matches = await unitInValueService . Get ( ) . AsNoTracking ( )
var matches = await _ unitInValueService. Get ( ) . AsNoTracking ( )
. Where ( uiv = > uiv . FieldId = = responsableAreaFieldId & & distinctResponsableAreaValues . Contains ( uiv . ValueId ) )
. Join (
unitInValueService . Get ( ) . AsNoTracking ( ) . Where ( t = > t . FieldId = = tagFieldId & & t . ValueId = = targetTagValueId ) ,
_ unitInValueService. Get ( ) . AsNoTracking ( ) . Where ( t = > t . FieldId = = tagFieldId & & t . ValueId = = targetTagValueId ) ,
responsableArea = > responsableArea . UnitId ,
tag = > tag . UnitId ,
( responsableArea , tag ) = > new { responsableArea . ValueId , responsableArea . UnitId }
@@ -404,7 +393,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
. GroupBy ( x = > x . ValueId )
. ToDictionary ( g = > g . Key , g = > g . First ( ) . UnitId ) ;
logger . LogDebug ( "Сформирован кэш соответствий: найдено {Count} целевых юнитов." , responsableAreaToTargetUnitMap . Count ) ;
_ logger. LogDebug ( "Сформирован кэш соответствий: найдено {Count} целевых юнитов." , responsableAreaToTargetUnitMap . Count ) ;
}
foreach ( var template in unusedTemplates )
@@ -416,7 +405,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
if ( template . Unit = = null )
{
logger . LogWarning ( "У шаблона {TemplateId} отсутствует Unit. Пропускаем." , template . Id ) ;
_ logger. LogWarning ( "У шаблона {TemplateId} отсутствует Unit. Пропускаем." , template . Id ) ;
processed + + ;
continue ;
}
@@ -441,11 +430,11 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
if ( targetUnitId . HasValue & & targetUnitId . Value ! = template . UnitId )
{
logger . LogInformation ( "Для шаблона {TemplateId} найден новый UnitId {NewUnitId} (был {OldUnitId})." ,
_ logger. LogInformation ( "Для шаблона {TemplateId} найден новый UnitId {NewUnitId} (был {OldUnitId})." ,
template . Id , targetUnitId . Value , template . UnitId ) ;
// Передаем ct в запрос
var newUnit = await unitRepository . Get ( ) . AsNoTracking ( )
var newUnit = await _ unitRepository. Get ( ) . AsNoTracking ( )
. FirstOrDefaultAsync ( u = > u . Id = = targetUnitId . Value , ct ) ;
if ( newUnit ! = null )
@@ -454,13 +443,13 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
}
else
{
logger . LogWarning ( "Н е удалось загрузить новый юнит {UnitId}. Используем старый." , targetUnitId . Value ) ;
_ logger. LogWarning ( "Н е удалось загрузить новый юнит {UnitId}. Используем старый." , targetUnitId . Value ) ;
finalUnitId = template . UnitId ;
}
}
else if ( ! hasResponsableArea )
{
logger . LogDebug ( "У юнита {UnitId} шаблона {TemplateId} нет значения поля З О Н А _О Т В Е Т С Т В Е Н Н О С Т И. Оставляем текущий UnitId." , template . UnitId , template . Id ) ;
_ logger. LogDebug ( "У юнита {UnitId} шаблона {TemplateId} нет значения поля З О Н А _О Т В Е Т С Т В Е Н Н О С Т И. Оставляем текущий UnitId." , template . UnitId , template . Id ) ;
}
// 4. Генерация целевого имени
@@ -473,30 +462,43 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
if ( ! unitChanged & & ! jobChanged & & ! nameChanged )
{
logger . LogDebug ( "Шаблон {TemplateId} уже актуален. Пропуск отправки в MQ." , template . Id ) ;
_ logger. LogDebug ( "Шаблон {TemplateId} уже актуален. Пропуск отправки в MQ." , template . Id ) ;
processed + + ;
continue ;
}
await SendUpdateRequest ( template , unusedJobId , expectedName , initiator , finalUnitId ) ;
logger . LogDebug ( "Отправлен запрос на обновление шаблона {TemplateId}. Изменения: Unit={U}, Job={J}, Name={N}" ,
_ logger. LogDebug ( "Отправлен запрос на обновление шаблона {TemplateId}. Изменения: Unit={U}, Job={J}, Name={N}" ,
template . Id , unitChanged , jobChanged , nameChanged ) ;
processed + + ;
}
catch ( Exception ex )
{
logger . LogError ( ex , "Ошибка при обработке шаблона {TemplateId}" , template . Id ) ;
_ logger. LogError ( ex , "Ошибка при обработке шаблона {TemplateId}" , template . Id ) ;
}
}
totalSw . Stop ( ) ;
totalSw . Stop ( ) ;
_logger . LogInformation ( "[Perf] Job '{JobName}' ({JobId}) | ИТОГО: {TotalMs} мс" ,
unusedJob . Name , unusedJob . Id , totalSw . ElapsedMilliseconds ) ;
await UpdateMatchingStatusAsync ( unusedJobId , "Синхронизация неиспользуемых шаблонов завершена" ) ;
await matchingStatusService . DeleteMatchingStatusAsync ( unusedJobId , SyncTaskEntityTypeEnum . Job ) ;
logger . LogInformation ( "Синхронизация неиспользуемых шаблонов завершена. Обработано {Count} шаблонов." , unusedTemplates . Count ) ;
await _ matchingStatusService. DeleteMatchingStatusAsync ( unusedJobId , SyncTaskEntityTypeEnum . Job ) ;
totalSw . Stop ( ) ;
_logger . LogInformation (
"Синхронизация неиспользуемых шаблонов завершена. Обработано {Count} шаблонов" ,
unusedTemplates . Count ) ;
}
catch ( Exception ex )
{
logger . LogError ( ex , "Ошибка при синхронизации неиспользуемых шаблонов для Job {JobId}" , unusedJobId ) ;
totalSw . Stop ( ) ;
_logger . LogError ( ex ,
"Ошибка при синхронизации неиспользуемых шаблонов для Job {JobId} через {ElapsedMs} мс" ,
unusedJobId , totalSw . ElapsedMilliseconds ) ;
await UpdateMatchingStatusAsync ( unusedJobId , $"Ошибка: {ex.Message}" ) ;
throw ;
}
@@ -520,7 +522,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
UnitsInTemplate = new List < UnitInTemplateMessage > ( )
} ;
await templateMqPublisher . PublishUpdateAsync ( updateRequest ) ;
await _ templateMqPublisher. PublishUpdateAsync ( updateRequest ) ;
}
@@ -534,7 +536,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
MinValueRelationships = unusedJob . MinValueRelationships ,
MaxValueRelationships = unusedJob . MaxValueRelationships ,
IsParentRelationships = unusedJob . IsParentRelationships ,
TemplateNameMask = templateSettings . Value . UnusedTemplateNameMask ,
TemplateNameMask = _ templateSettings. Value . UnusedTemplateNameMask ,
WorkGroupMask = unusedJob . WorkGroupMask ,
ResponseAreaMask = unusedJob . ResponseAreaMask ,
TnkId = unusedJob . TnkId ,
@@ -558,26 +560,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
UnitsInTemplate = new List < UnitsInTemplate > ( )
} ;
return await templateNameNormalizer . GetNormalizedTemplateNameAsync ( tempTemplateForName ) ;
}
private async Task CreateSimpleTemplateAsync ( Guid jobId , Guid unitId , HistoryInitiator initiator )
{
logger . LogInformation ( "Создание нового простого шаблона для Job {JobId}, UnitId {UnitId}." , jobId , unitId ) ;
var mqRequest = new TemplateGeneratorMessage
{
JobId = jobId ,
UnitId = unitId ,
UnitsInTemplate = new List < UnitInTemplateMessage > ( ) , // для простого шаблона
HistoryInitiator = initiator
} ;
var result = await mqService . SendAsync ( mqSettings . TemplateGenerator , new List < object > { mqRequest } ) ;
if ( ! result . IsSuccess )
logger . LogError ( "Ошибка отправки команды создания простого шаблона для Job {JobId}, UnitId {UnitId}." , jobId , unitId ) ;
return await _ templateNameNormalizer. GetNormalizedTemplateNameAsync ( tempTemplateForName ) ;
}
@@ -589,7 +572,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
Action = TemplateMatcherActionEnum . Sync ,
Comment = comment
} ;
await matchingStatusService . SetMatchingStatusAsync (
await _ matchingStatusService. SetMatchingStatusAsync (
jobId ,
SyncTaskEntityTypeEnum . Job ,
new MatchingStatusItem { Data = status , Timestamp = DateTimeOffset . UtcNow , Source = nameof ( SimpleTemplateSynchronizer ) } ,