feat(tempateMatcher): в матчеры добавлено взаимодействие с MatchingStatusService, для отображения статуса операции

This commit is contained in:
Mikhail Kuznetsov
2026-01-16 19:45:38 +10:00
parent d91877453a
commit 5eb0ab81b9
2 changed files with 936 additions and 781 deletions

View File

@@ -4,6 +4,7 @@ using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces; using PARR.BLL.Services.Interfaces;
using PARR.Common.Domain; using PARR.Common.Domain;
using PARR.Constants; using PARR.Constants;
using PARR.DAL.Cache.Models;
using PARR.DAL.DomainServices.Interfaces; using PARR.DAL.DomainServices.Interfaces;
using PARR.DAL.DomainServices.Shortcodes; using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models; using PARR.DAL.Models;
@@ -38,6 +39,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
private readonly ITemplateDeactivator templateDeactivator; private readonly ITemplateDeactivator templateDeactivator;
private readonly ITemplateNameNormalizer templateNameNormalizer; private readonly ITemplateNameNormalizer templateNameNormalizer;
private readonly ITemplateUpdaterMqSender templateUpdaterMqSender; private readonly ITemplateUpdaterMqSender templateUpdaterMqSender;
private readonly IMatchingStatusService matchingStatusService;
public SimpleTemplateSynchronizer( public SimpleTemplateSynchronizer(
ILogger<SimpleTemplateSynchronizer> logger, ILogger<SimpleTemplateSynchronizer> logger,
@@ -56,7 +58,8 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
IUnitFieldService unitFieldService, IUnitFieldService unitFieldService,
ITemplateDeactivator templateDeactivator, ITemplateDeactivator templateDeactivator,
ITemplateNameNormalizer templateNameNormalizer, ITemplateNameNormalizer templateNameNormalizer,
ITemplateUpdaterMqSender templateUpdaterMqSender ITemplateUpdaterMqSender templateUpdaterMqSender,
IMatchingStatusService matchingStatusService
) )
{ {
this.logger = logger; this.logger = logger;
@@ -70,174 +73,237 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
this.templateDeactivator = templateDeactivator; this.templateDeactivator = templateDeactivator;
this.templateNameNormalizer = templateNameNormalizer; this.templateNameNormalizer = templateNameNormalizer;
this.templateUpdaterMqSender = templateUpdaterMqSender; this.templateUpdaterMqSender = templateUpdaterMqSender;
this.matchingStatusService = matchingStatusService;
} }
public async Task SyncTemplatesForJobAsync(Guid jobId, HistoryInitiator initiator) public async Task SyncTemplatesForJobAsync(Guid jobId, HistoryInitiator initiator)
{ {
logger.LogDebug("Начало синхронизации шаблонов для Job {JobId}", jobId); logger.LogDebug("Начало синхронизации шаблонов для Job {JobId}", jobId);
var job = await jobService.Get() // === Проверка: уже запущена? ===
.AsNoTracking() var existingStatus = await matchingStatusService.GetStatusAsync(jobId, SyncTaskEntityTypeEnum.Job);
.Include(j => j.AutoControl) if (existingStatus.DetailsJobs?.Any() == true)
.Include(j => j.Tnk)
.Include(j => j.Group)
.ThenInclude(g => g!.GroupType)
.Include(j => j.UnitFilters)
.ThenInclude(uf => uf.RelationshipFilters)
.FirstOrDefaultAsync(j => j.Id == jobId);
if (job == null)
{ {
logger.LogWarning("Job {JobId} не найден.", jobId); logger.LogWarning("Синхронизация для Job {JobId} уже запущена. Пропускаем.", jobId);
return; return;
} }
var unitIds = await unitFilterService.GetUnitsIdByJobFilterAsync(jobId); // === Устанавливаем статус "в процессе" ===
if (unitIds == null || !unitIds.Any()) var initialStatus = new MatchingStatusItemDto
{ {
logger.LogInformation("Для Job {JobId} фильтры не дали Unit'ов.", jobId); DateStart = DateTimeOffset.UtcNow,
Action = TemplateMatcherActionEnum.Sync,
Comment = "Начало синхронизации"
};
await matchingStatusService.SetMatchingStatusAsync(
jobId,
SyncTaskEntityTypeEnum.Job,
new MatchingStatusItem { Data = initialStatus, Timestamp = DateTimeOffset.UtcNow, Source = nameof(SimpleTemplateSynchronizer) },
TimeSpan.FromMinutes(35)
);
// Деактивировать все существующие шаблоны для этого Job try
var existingTemplatesForDeactivation = await templateService.Get() {
var job = await jobService.Get()
.AsNoTracking() .AsNoTracking()
.Include(t => t.UnitsInTemplate) .Include(j => j.AutoControl)
.Where(t => t.JobId == jobId && t.StatusTypeId == TemplateStatusTypeEnum.Used) .Include(j => j.Tnk)
.ToListAsync(); .Include(j => j.Group)
.ThenInclude(g => g!.GroupType)
.Include(j => j.UnitFilters)
.ThenInclude(uf => uf.RelationshipFilters)
.FirstOrDefaultAsync(j => j.Id == jobId);
foreach (var unusedTemplate in existingTemplatesForDeactivation) if (job == null)
{ {
logger.LogInformation("Деактивация лишнего шаблона {TemplateId} (Job {JobId}, UnitId {UnitId}).", unusedTemplate.Id, jobId, unusedTemplate.UnitId); logger.LogWarning("Job {JobId} не найден.", jobId);
await templateDeactivator.DeactivateTemplateAsync(unusedTemplate, initiator); await UpdateMatchingStatusAsync(jobId, "Job не найден");
return;
} }
logger.LogInformation("Синхронизация шаблонов завершена для Job {JobId}.", jobId); var unitIds = await unitFilterService.GetUnitsIdByJobFilterAsync(jobId);
return;
}
#if DEBUG
// Отладка: проверить, есть ли юнит в unitIds
if (unitIds.Contains(targetUnitId))
{
logger.LogDebug("Юнит {TargetUnitId} найден в unitIds.", targetUnitId);
}
else
{
logger.LogDebug("Юнит {TargetUnitId} НЕ найден в unitIds.", targetUnitId);
}
#endif
var existingTemplates = await templateService.Get()
.Include(t => t.UnitsInTemplate)
.Include(t => t.Job)
.ThenInclude(t => t!.Group)
.ThenInclude(t => t.GroupType)
.Include(t => t.Job)
.ThenInclude(t => t!.Tnk)
.Include(t => t.Unit)
.Where(t => t.JobId == jobId)
.ToListAsync();
var existingUsedTemplates = existingTemplates
.Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Used)
.ToList();
var existingUnitIds = existingUsedTemplates
.Select(t => t.UnitId)
.ToHashSet();
var newUnitIds = unitIds.Except(existingUnitIds).ToList();
var unusedTemplates = existingUsedTemplates
.Where(t => !unitIds.Contains(t.UnitId))
.ToList();
// Обработка новых юнитов
foreach (var unitId in newUnitIds)
{
var reusableTemplate = await templateReuser.TryReuseOneUnusedTemplateAsync(jobId, unitId, initiator);
if (reusableTemplate != null)
{ {
logger.LogInformation("Переиспользован шаблон {TemplateId} для Job {JobId}, UnitId {UnitId}.", reusableTemplate.Id, jobId, unitId); if (unitIds == null || !unitIds.Any())
// === Создаём временный Template для нормализации имени ===
var tempTemplateForName = new Template
{ {
Id = reusableTemplate.Id, logger.LogInformation("Для Job {JobId} фильтры не дали Unit'ов.", jobId);
Name = reusableTemplate.Name,
JobId = jobId,
UnitId = unitId,
Index = reusableTemplate.Index,
Job = job, // загруженный job
Unit = reusableTemplate.Unit, // может быть null — нормально
UnitsInTemplate = new List<UnitsInTemplate>() // для простого шаблона
};
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(tempTemplateForName); var existingTemplatesForDeactivation = await templateService.Get()
var nextRun = await GetNextRunAsync(job); .AsNoTracking()
.Include(t => t.UnitsInTemplate)
.Where(t => t.JobId == jobId && t.StatusTypeId == TemplateStatusTypeEnum.Used)
.ToListAsync();
var updateRequest = new TemplateUpdaterMq await UpdateMatchingStatusAsync(jobId, $"Нет Unit'ов. Деактивация {existingTemplatesForDeactivation.Count} шаблонов...");
{
TemplateId = reusableTemplate.Id,
JobId = jobId,
UnitId = unitId,
Name = expectedName,
IsActiveTemplate = job.AutoControl?.InitUsedTemplateState ?? DefaultUsedTemplateState,
IsActiveSchedule = job.AutoControl?.InitUsedScheduleState ?? DefaultUsedScheduleState,
StatusTypeId = TemplateStatusTypeEnum.Used,
Initiator = initiator,
NextRun = nextRun,
UnitsInTemplate = new List<Guid>() // для простого шаблона
};
await templateUpdaterMqSender.SendTemplateUpdateMessageAsync(updateRequest); foreach (var unusedTemplate in existingTemplatesForDeactivation)
{
logger.LogInformation("Деактивация лишнего шаблона {TemplateId} (Job {JobId}, UnitId {UnitId}).", unusedTemplate.Id, jobId, unusedTemplate.UnitId);
await templateDeactivator.DeactivateTemplateAsync(unusedTemplate, initiator);
}
await UpdateMatchingStatusAsync(jobId, "Синхронизация завершена: нет Unit'ов");
await matchingStatusService.DeleteMatchingStatusAsync(jobId, SyncTaskEntityTypeEnum.Job);
logger.LogInformation("Синхронизация шаблонов завершена для Job {JobId}.", jobId);
return;
}
}
#if DEBUG
if (unitIds.Contains(targetUnitId))
{
logger.LogDebug("Юнит {TargetUnitId} найден в unitIds.", targetUnitId);
} }
else else
{ {
logger.LogDebug("Создание нового шаблона для Job {JobId}, UnitId {UnitId}.", jobId, unitId); logger.LogDebug("Юнит {TargetUnitId} НЕ найден в unitIds.", targetUnitId);
await CreateSimpleTemplateAsync(jobId, unitId, initiator);
} }
} #endif
// Обработка существующих шаблонов (проверка имени) var existingTemplates = await templateService.Get()
foreach (var template in existingUsedTemplates) .Include(t => t.UnitsInTemplate)
{ .Include(t => t.Job)
if (unitIds.Contains(template.UnitId)) .ThenInclude(t => t!.Group)
.ThenInclude(t => t.GroupType)
.Include(t => t.Job)
.ThenInclude(t => t!.Tnk)
.Include(t => t.Unit)
.Where(t => t.JobId == jobId)
.ToListAsync();
var existingUsedTemplates = existingTemplates
.Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Used)
.ToList();
var existingUnitIds = existingUsedTemplates
.Select(t => t.UnitId)
.ToHashSet();
var newUnitIds = unitIds.Except(existingUnitIds).ToList();
var unusedTemplates = existingUsedTemplates
.Where(t => !unitIds.Contains(t.UnitId))
.ToList();
// === Подсчёт операций ===
int toCreate = newUnitIds.Count;
int toUpdate = 0;
int toDeactivate = unusedTemplates.Count;
// Подсчёт обновлений по имени
foreach (var template in existingUsedTemplates)
{ {
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(template); if (unitIds.Contains(template.UnitId))
if (!string.Equals(template.Name, expectedName, StringComparison.OrdinalIgnoreCase))
{ {
logger.LogDebug("Шаблон {TemplateId} требует обновления имени: старое = '{OldName}', новое = '{NewName}'", template.Id, template.Name, expectedName); var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(template);
if (!string.Equals(template.Name, expectedName, StringComparison.OrdinalIgnoreCase))
toUpdate++;
}
}
var nextRun = await GetNextRunAsync(job, template.NextRun); await UpdateMatchingStatusAsync(jobId, $"Осталось: создать={toCreate}, обновить={toUpdate}, деактивировать={toDeactivate}");
// === Обработка новых юнитов ===
int created = 0, updated = 0, deactivated = 0;
foreach (var unitId in newUnitIds)
{
var reusableTemplate = await templateReuser.TryReuseOneUnusedTemplateAsync(jobId, unitId, initiator);
if (reusableTemplate != null)
{
logger.LogInformation("Переиспользован шаблон {TemplateId} для Job {JobId}, UnitId {UnitId}.", reusableTemplate.Id, jobId, unitId);
var tempTemplateForName = new Template
{
Id = reusableTemplate.Id,
Name = reusableTemplate.Name,
JobId = jobId,
UnitId = unitId,
Index = reusableTemplate.Index,
Job = job,
Unit = reusableTemplate.Unit,
UnitsInTemplate = new List<UnitsInTemplate>()
};
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(tempTemplateForName);
var nextRun = await GetNextRunAsync(job);
var updateRequest = new TemplateUpdaterMq var updateRequest = new TemplateUpdaterMq
{ {
TemplateId = template.Id, TemplateId = reusableTemplate.Id,
JobId = jobId, JobId = jobId,
UnitId = template.UnitId, UnitId = unitId,
Name = expectedName, Name = expectedName,
IsActiveTemplate = template.IsActiveTemplate, IsActiveTemplate = job.AutoControl?.InitUsedTemplateState ?? DefaultUsedTemplateState,
IsActiveSchedule = template.IsActiveSchedule, IsActiveSchedule = job.AutoControl?.InitUsedScheduleState ?? DefaultUsedScheduleState,
LastRun = template.LastRun,
NextRun = nextRun,
Index = template.Index,
StatusTypeId = TemplateStatusTypeEnum.Used, StatusTypeId = TemplateStatusTypeEnum.Used,
Initiator = initiator, Initiator = initiator,
UnitsInTemplate = new List<Guid>() // для простого шаблона NextRun = nextRun,
UnitsInTemplate = new List<Guid>()
}; };
await templateUpdaterMqSender.SendTemplateUpdateMessageAsync(updateRequest); await templateUpdaterMqSender.SendTemplateUpdateMessageAsync(updateRequest);
} }
else
{
logger.LogDebug("Создание нового шаблона для Job {JobId}, UnitId {UnitId}.", jobId, unitId);
await CreateSimpleTemplateAsync(jobId, unitId, initiator);
}
created++;
await UpdateMatchingStatusAsync(jobId, $"Прогресс: создано={created}, обновлено={updated}, деактивировано={deactivated}. Осталось: создать={toCreate - created}, обновить={toUpdate - updated}, деактивировать={toDeactivate - deactivated}");
} }
}
// Деактивация лишних шаблонов // === Обработка существующих шаблонов (проверка имени) ===
foreach (var unusedTemplate in unusedTemplates) foreach (var template in existingUsedTemplates)
{
if (unitIds.Contains(template.UnitId))
{
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(template);
if (!string.Equals(template.Name, expectedName, StringComparison.OrdinalIgnoreCase))
{
logger.LogDebug("Шаблон {TemplateId} требует обновления имени.", template.Id);
var nextRun = await GetNextRunAsync(job, template.NextRun);
var updateRequest = new TemplateUpdaterMq
{
TemplateId = template.Id,
JobId = jobId,
UnitId = template.UnitId,
Name = expectedName,
IsActiveTemplate = template.IsActiveTemplate,
IsActiveSchedule = template.IsActiveSchedule,
LastRun = template.LastRun,
NextRun = nextRun,
Index = template.Index,
StatusTypeId = TemplateStatusTypeEnum.Used,
Initiator = initiator,
UnitsInTemplate = new List<Guid>()
};
await templateUpdaterMqSender.SendTemplateUpdateMessageAsync(updateRequest);
updated++;
await UpdateMatchingStatusAsync(jobId, $"Прогресс: создано={created}, обновлено={updated}, деактивировано={deactivated}. Осталось: создать={toCreate - created}, обновить={toUpdate - updated}, деактивировать={toDeactivate - deactivated}");
}
}
}
// === Деактивация лишних шаблонов ===
foreach (var unusedTemplate in unusedTemplates)
{
logger.LogInformation("Деактивация лишнего шаблона {TemplateId} (Job {JobId}, UnitId {UnitId}).", unusedTemplate.Id, jobId, unusedTemplate.UnitId);
await templateDeactivator.DeactivateTemplateAsync(unusedTemplate, initiator);
deactivated++;
await UpdateMatchingStatusAsync(jobId, $"Прогресс: создано={created}, обновлено={updated}, деактивировано={deactivated}. Осталось: создать={toCreate - created}, обновить={toUpdate - updated}, деактивировать={toDeactivate - deactivated}");
}
// === Успешное завершение ===
await UpdateMatchingStatusAsync(jobId, "Синхронизация завершена успешно");
await matchingStatusService.DeleteMatchingStatusAsync(jobId, SyncTaskEntityTypeEnum.Job);
logger.LogInformation("Синхронизация шаблонов завершена для Job {JobId}.", jobId);
}
catch (Exception ex)
{ {
logger.LogInformation("Деактивация лишнего шаблона {TemplateId} (Job {JobId}, UnitId {UnitId}).", unusedTemplate.Id, jobId, unusedTemplate.UnitId); logger.LogError(ex, "Ошибка при синхронизации Job {JobId}", jobId);
await templateDeactivator.DeactivateTemplateAsync(unusedTemplate, initiator); await UpdateMatchingStatusAsync(jobId, $"Ошибка: {ex.Message}");
throw;
} }
logger.LogInformation("Синхронизация шаблонов завершена для Job {JobId}.", jobId);
} }
public async Task SyncTemplatesForJobGroupAsync(Guid jobGroupId, HistoryInitiator initiator) public async Task SyncTemplatesForJobGroupAsync(Guid jobGroupId, HistoryInitiator initiator)
@@ -249,86 +315,136 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
{ {
logger.LogDebug("Обновление шаблонов для Job {JobId}", jobId); logger.LogDebug("Обновление шаблонов для Job {JobId}", jobId);
var job = await jobService.Get() // === Проверка: уже запущена? ===
.AsNoTracking() var existingStatus = await matchingStatusService.GetStatusAsync(jobId, SyncTaskEntityTypeEnum.Job);
.Include(j => j.AutoControl) if (existingStatus.DetailsJobs?.Any() == true)
.Include(j => j.Tnk)
.Include(j => j.Group)
.ThenInclude(g => g!.GroupType)
.Include(j => j.UnitFilters)
.ThenInclude(uf => uf.RelationshipFilters)
.FirstOrDefaultAsync(j => j.Id == jobId);
if (job == null)
{ {
logger.LogWarning("Job {JobId} не найден.", jobId); logger.LogWarning("Обновление для Job {JobId} уже запущено. Пропускаем.", jobId);
return; return;
} }
var unitIds = await unitFilterService.GetUnitsIdByJobFilterAsync(jobId); var initialStatus = new MatchingStatusItemDto
if (unitIds == null || !unitIds.Any())
{ {
logger.LogInformation("Для Job {JobId} фильтры не дали Unit'ов.", jobId); DateStart = DateTimeOffset.UtcNow,
return; Action = TemplateMatcherActionEnum.Update,
} Comment = "Начало обновления имён"
};
await matchingStatusService.SetMatchingStatusAsync(
jobId,
SyncTaskEntityTypeEnum.Job,
new MatchingStatusItem { Data = initialStatus, Timestamp = DateTimeOffset.UtcNow, Source = nameof(SimpleTemplateSynchronizer) },
TimeSpan.FromMinutes(30)
);
try
{
var job = await jobService.Get()
.AsNoTracking()
.Include(j => j.AutoControl)
.Include(j => j.Tnk)
.Include(j => j.Group)
.ThenInclude(g => g!.GroupType)
.Include(j => j.UnitFilters)
.ThenInclude(uf => uf.RelationshipFilters)
.FirstOrDefaultAsync(j => j.Id == jobId);
if (job == null)
{
logger.LogWarning("Job {JobId} не найден.", jobId);
await UpdateMatchingStatusAsync(jobId, "Job не найден");
return;
}
var unitIds = await unitFilterService.GetUnitsIdByJobFilterAsync(jobId);
if (unitIds == null || !unitIds.Any())
{
logger.LogInformation("Для Job {JobId} фильтры не дали Unit'ов.", jobId);
await UpdateMatchingStatusAsync(jobId, "Нет Unit'ов — обновление не требуется");
await matchingStatusService.DeleteMatchingStatusAsync(jobId, SyncTaskEntityTypeEnum.Job);
return;
}
#if DEBUG #if DEBUG
// Отладка: проверить, есть ли юнит в unitIds if (unitIds.Contains(targetUnitId))
if (unitIds.Contains(targetUnitId)) {
{ logger.LogDebug("Юнит {TargetUnitId} найден в unitIds.", targetUnitId);
logger.LogDebug("Юнит {TargetUnitId} найден в unitIds.", targetUnitId); }
} else
else {
{ logger.LogDebug("Юнит {TargetUnitId} НЕ найден в unitIds.", targetUnitId);
logger.LogDebug("Юнит {TargetUnitId} НЕ найден в unitIds.", targetUnitId); }
}
#endif #endif
var existingTemplates = await templateService.Get() var existingTemplates = await templateService.Get()
.AsNoTracking() .AsNoTracking()
.Include(t => t.Unit) .Include(t => t.Unit)
.Include(t => t.UnitsInTemplate) .Include(t => t.UnitsInTemplate)
.Include(t => t.Job) .Include(t => t.Job)
.ThenInclude(t => t!.Group) .ThenInclude(t => t!.Group)
.ThenInclude(t => t!.GroupType) .ThenInclude(t => t!.GroupType)
.Include(t => t.Job) .Include(t => t.Job)
.ThenInclude(t => t!.Tnk) .ThenInclude(t => t!.Tnk)
.Where(t => t.JobId == jobId && t.StatusTypeId == TemplateStatusTypeEnum.Used) .Where(t => t.JobId == jobId && t.StatusTypeId == TemplateStatusTypeEnum.Used)
.ToListAsync(); .ToListAsync();
foreach (var template in existingTemplates) int toUpdate = 0;
{ foreach (var template in existingTemplates)
if (unitIds.Contains(template.UnitId))
{ {
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(template); if (unitIds.Contains(template.UnitId))
if (!string.Equals(template.Name, expectedName, StringComparison.OrdinalIgnoreCase))
{ {
logger.LogDebug("Шаблон {TemplateId} требует обновления имени: старое = '{OldName}', новое = '{NewName}'", template.Id, template.Name, expectedName); var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(template);
if (!string.Equals(template.Name, expectedName, StringComparison.OrdinalIgnoreCase))
var nextRun = await GetNextRunAsync(job, template.NextRun); toUpdate++;
var updateRequest = new TemplateUpdaterMq
{
TemplateId = template.Id,
JobId = jobId,
UnitId = template.UnitId,
Name = expectedName,
IsActiveTemplate = template.IsActiveTemplate,
IsActiveSchedule = template.IsActiveSchedule,
LastRun = template.LastRun,
NextRun = nextRun,
Index = template.Index,
StatusTypeId = TemplateStatusTypeEnum.Used,
Initiator = initiator,
UnitsInTemplate = new List<Guid>() // для простого шаблона
};
await templateUpdaterMqSender.SendTemplateUpdateMessageAsync(updateRequest);
} }
} }
}
logger.LogInformation("Обновление шаблонов завершено для Job {JobId}.", jobId); await UpdateMatchingStatusAsync(jobId, $"Обновление имён: {toUpdate} шаблонов");
int updated = 0;
foreach (var template in existingTemplates)
{
if (unitIds.Contains(template.UnitId))
{
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(template);
if (!string.Equals(template.Name, expectedName, StringComparison.OrdinalIgnoreCase))
{
logger.LogDebug("Шаблон {TemplateId} требует обновления имени.", template.Id);
var nextRun = await GetNextRunAsync(job, template.NextRun);
var updateRequest = new TemplateUpdaterMq
{
TemplateId = template.Id,
JobId = jobId,
UnitId = template.UnitId,
Name = expectedName,
IsActiveTemplate = template.IsActiveTemplate,
IsActiveSchedule = template.IsActiveSchedule,
LastRun = template.LastRun,
NextRun = nextRun,
Index = template.Index,
StatusTypeId = TemplateStatusTypeEnum.Used,
Initiator = initiator,
UnitsInTemplate = new List<Guid>()
};
await templateUpdaterMqSender.SendTemplateUpdateMessageAsync(updateRequest);
updated++;
await UpdateMatchingStatusAsync(jobId, $"Обновлено: {updated}/{toUpdate}");
}
}
}
await UpdateMatchingStatusAsync(jobId, "Обновление завершено");
await matchingStatusService.DeleteMatchingStatusAsync(jobId, SyncTaskEntityTypeEnum.Job);
logger.LogInformation("Обновление шаблонов завершено для Job {JobId}.", jobId);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка при обновлении Job {JobId}", jobId);
await UpdateMatchingStatusAsync(jobId, $"Ошибка: {ex.Message}");
throw;
}
} }
private async Task CreateSimpleTemplateAsync(Guid jobId, Guid unitId, HistoryInitiator initiator) private async Task CreateSimpleTemplateAsync(Guid jobId, Guid unitId, HistoryInitiator initiator)
@@ -339,7 +455,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
{ {
JobId = jobId, JobId = jobId,
UnitId = unitId, UnitId = unitId,
UnitsInTemplate = new List<Guid>(), // для простого шаблона UnitsInTemplate = new List<Guid>(),
HistoryInitiator = initiator HistoryInitiator = initiator
}; };
@@ -355,4 +471,20 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
var referenceDate = job.Group?.ReferenceDate ?? DateTimeOffset.UtcNow; var referenceDate = job.Group?.ReferenceDate ?? DateTimeOffset.UtcNow;
return await esppScheduleTransformService.GetNextDateAsync(job.GroupId, referenceDate); return await esppScheduleTransformService.GetNextDateAsync(job.GroupId, referenceDate);
} }
private async Task UpdateMatchingStatusAsync(Guid jobId, string comment)
{
var status = new MatchingStatusItemDto
{
DateStart = DateTimeOffset.UtcNow,
Action = TemplateMatcherActionEnum.Sync,
Comment = comment
};
await matchingStatusService.SetMatchingStatusAsync(
jobId,
SyncTaskEntityTypeEnum.Job,
new MatchingStatusItem { Data = status, Timestamp = DateTimeOffset.UtcNow, Source = nameof(SimpleTemplateSynchronizer) },
TimeSpan.FromMinutes(30)
);
}
} }