feat(dal,core): Рефакторинг методов и логики выдачи заданий роботом при переименовании шаблонов
This commit is contained in:
@@ -48,13 +48,13 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
||||
ITemplateRenamePendingRepository templateRenamePendingRepository
|
||||
)
|
||||
{
|
||||
this._logger = logger;
|
||||
this._robotConfigurationRepository = robotConfigurationRepository;
|
||||
this._settingsFromDb = settingsFromDb;
|
||||
this._robotHistoryRepository = robotHistoryRepository;
|
||||
this._mapper = mapper;
|
||||
this._shortcodesService = shortcodesService;
|
||||
this._nextRunService = nextRunService;
|
||||
_logger = logger;
|
||||
_robotConfigurationRepository = robotConfigurationRepository;
|
||||
_settingsFromDb = settingsFromDb;
|
||||
_robotHistoryRepository = robotHistoryRepository;
|
||||
_mapper = mapper;
|
||||
_shortcodesService = shortcodesService;
|
||||
_nextRunService = nextRunService;
|
||||
_templateRenamePendingRepository = templateRenamePendingRepository;
|
||||
}
|
||||
|
||||
@@ -264,17 +264,18 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
||||
|
||||
|
||||
// Ищем есть ли связанные шаблоны с таким имененм на переименование
|
||||
var taskTemplateNames = tasks.Select(t => t.TemplateName);
|
||||
var taskTemplateNames = tasks.Select(t => t.TemplateName).Distinct().ToList();
|
||||
// Ищем записи в таблице переименований, где OldName совпадает с именами наших новых задач
|
||||
var templatesToRename = await _templateRenamePendingRepository.Get().AsNoTracking()
|
||||
.Where(t => taskTemplateNames.Contains(t.OldName))
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogDebug("Шаблонов для переименования в текущем задании: {Count} шт.", templatesToRename.Count);
|
||||
_logger.LogDebug("Найдено шаблонов в процессе переименования для текущих задач: {Count} шт.", templatesToRename.Count);
|
||||
|
||||
if (templatesToRename.Count == 0)
|
||||
return tasks;
|
||||
|
||||
// Ищем связанные переименованные шаблоны по ИД, смотрим можем ли взять их в работу
|
||||
// Ищем конфигурации роботов для СТАРЫХ шаблонов (которые переименовываются) по ИД, смотрим, можем ли взять их в работу
|
||||
var renameTemplateIds = templatesToRename.Select(t => t.TemplateId).ToList();
|
||||
var renameTasks = await _robotConfigurationRepository.Get()
|
||||
.AsNoTracking()
|
||||
@@ -286,63 +287,93 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
||||
&& t.TaskStatusCode == (int)TaskStatusEnum.Updating
|
||||
).ToListAsync();
|
||||
|
||||
// Ищем связанные задания которые в ошибке, и ставим целевому шаблону задание в ошибку
|
||||
var errorTasks = renameTasks.Where(t => t.RobotStatusCode == (int)RobotStatusEnum.Error && t.AttemptsNumber >= _settingsFromDb.RobotAttemptsNumber).ToList();
|
||||
// --- Блок обработки ошибок ---
|
||||
|
||||
// Если старый шаблон в ошибке и лимит попыток исчерпан, ставим ошибку и новому шаблону
|
||||
var errorTasks = renameTasks
|
||||
.Where(t =>
|
||||
t.RobotStatusCode == (int)RobotStatusEnum.Error
|
||||
&& t.AttemptsNumber >= _settingsFromDb.RobotAttemptsNumber
|
||||
).ToList();
|
||||
|
||||
var tasksToSetErrorStatus = new List<Guid>();
|
||||
if (errorTasks.Count > 0)
|
||||
{
|
||||
_logger.LogDebug("Найдено связанных заданий на переименование с ошибками: {ErrorCount}. Будем целевым шаблонам тоже ставить статус ошибки.", errorTasks.Count);
|
||||
_logger.LogDebug("Найдено старых заданий на переименование с ошибками: {ErrorCount}. Ставим ошибку целевым (новым) заданиям.", errorTasks.Count);
|
||||
|
||||
var errorTemplateNames = errorTasks.Select(t => t.Template!.Name).ToList();
|
||||
var errorTemplateNames = errorTasks.Select(t => t.Template!.Name).ToHashSet();
|
||||
// Берем целевые таски, находим в них задания которым надо поставить ошибку
|
||||
tasksToSetErrorStatus = tasks.Where(t => errorTemplateNames.Contains(t.TemplateName)).Select(t => t.TaskId).ToList();
|
||||
tasksToSetErrorStatus = tasks
|
||||
.Where(t => errorTemplateNames.Contains(t.TemplateName))
|
||||
.Select(t => t.TaskId)
|
||||
.ToList();
|
||||
|
||||
// Устанавливаем ошибку целевым + пишем комментарий от робота + нажимаем комит
|
||||
var logMessage = "[RobotTaskService] Установлен статус ошибки, так как не переименован связанный шаблон";
|
||||
await SetErrorStatusAsync(tasksToSetErrorStatus, logMessage);
|
||||
if (tasksToSetErrorStatus.Count > 0)
|
||||
{
|
||||
// Устанавливаем ошибку целевым + пишем комментарий от робота + нажимаем комит
|
||||
var logMessage = "[RobotTaskService] Установлен статус ошибки, так как не переименован связанный шаблон";
|
||||
await SetErrorStatusAsync(tasksToSetErrorStatus, logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Блок подмены задач ---
|
||||
|
||||
var endDate = DateTimeOffset.UtcNow.Add(-_settingsFromDb.RobotWaitTime);
|
||||
// Смотрим статусы роботов, можно взять в работу, только если (RobotStatus == Wait) или (InpRogress но которые еще не просрочены)
|
||||
var allowedTasks = renameTasks.Where(t =>
|
||||
|
||||
// Фильтруем старые задачи, которые МОЖНО взять в работу. Смотрим статусы роботов, можно взять в работу, только если (RobotStatus == Wait) или (InpRogress но которые еще не просрочены)
|
||||
var allowedRenameTasks = renameTasks.Where(t =>
|
||||
t.RobotStatusCode == (int)RobotStatusEnum.Wait
|
||||
|| (t.RobotStatusCode == (int)RobotStatusEnum.InProgress && t.AttemptsNumber < _settingsFromDb.RobotAttemptsNumber && t.LastRobotStatusUpdated < endDate)
|
||||
);
|
||||
|| (t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
||||
&& t.AttemptsNumber < _settingsFromDb.RobotAttemptsNumber
|
||||
&& t.LastRobotStatusUpdated < endDate)
|
||||
).ToList();
|
||||
|
||||
// Формируем список заданий
|
||||
// Словарь для поиска подменной задачи по имени шаблона.
|
||||
// GroupBy + First на случай, если в бд есть дубликаты, но такого быть не может
|
||||
var renameTasksToDictionary = allowedRenameTasks
|
||||
.GroupBy(t => t.Template!.Name)
|
||||
.ToDictionary(
|
||||
t => t.Key,
|
||||
t => new RobotTaskDetails(t.First().Id, t.First().Template!.Name, t.First().Template!.NextRun)
|
||||
);
|
||||
|
||||
var originalCount = tasks.Count; // Запоминаем сколько было изначально
|
||||
var errorTaskIdsSet = tasksToSetErrorStatus.ToHashSet();
|
||||
|
||||
// Из исходных тасков удалить те которым установлен статус ошибки
|
||||
var filteredOriginalTasks = tasks.Where(t => !tasksToSetErrorStatus.Contains(t.TaskId)).ToList();
|
||||
var errorCount = tasksToSetErrorStatus.Count; // Столько ушло в ошибку
|
||||
// Создаем итоговый список
|
||||
var finalTasks = new List<RobotTaskDetails>(tasks.Count);
|
||||
int replacedCount = 0;
|
||||
int errorCount = errorTaskIdsSet.Count;
|
||||
|
||||
// Определяем, какие имена шаблонов мы БУДЕМ подменять на задачи переименования
|
||||
var allowedRenameTemplateNames = allowedTasks.Select(t => t.Template!.Name).ToList();
|
||||
// Проходим по ИСХОДНОМУ списку, чтобы сохранить его порядок сортировки
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
// Если задаче нужно поставить ошибку, просто пропускаем ее (она не попадет в итоговый список)
|
||||
if (errorTaskIdsSet.Contains(task.TaskId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Из исходных удаляем те, которые мы сейчас заменим (подменим)
|
||||
var resultsTasks = filteredOriginalTasks.Where(t => !allowedRenameTemplateNames.Contains(t.TemplateName)).ToList();
|
||||
// Если для этого имени шаблона есть разрешенная задача на переименование - вставляем ее на место текущей
|
||||
if (renameTasksToDictionary.TryGetValue(task.TemplateName, out var renameTask))
|
||||
{
|
||||
finalTasks.Add(renameTask);
|
||||
replacedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Иначе оставляем исходную задачу на месте
|
||||
finalTasks.Add(task);
|
||||
}
|
||||
}
|
||||
|
||||
// Считаем сколько именно задач мы ВЫКИНУЛИ из исходного списка ради подмены
|
||||
var replacedCount = filteredOriginalTasks.Count - resultsTasks.Count;
|
||||
|
||||
// В исходные добавляем подменные таски для переименования (мапим их в RobotTaskDetails)
|
||||
var mappedRenameTasks = allowedTasks.Select(t => new RobotTaskDetails(t.Id, t.Template!.Name, t.Template.NextRun)).ToList();
|
||||
resultsTasks.AddRange(mappedRenameTasks);
|
||||
|
||||
var injectedCount = mappedRenameTasks.Count; // Столько задач переименования добавили взамен
|
||||
|
||||
// Логируем итоговую статистику трансформации пула задач
|
||||
// TODO: Позже этот лог можно понизить до Debug!!!
|
||||
_logger.LogInformation(
|
||||
"Трансформация пула задач завершена. Исходных: {OriginalCount} шт. " +
|
||||
"Отклонено (ошибка): {ErrorCount} шт. Удалено обычных для подмены: {ReplacedCount} шт. " +
|
||||
"Внедрено задач переименования: {InjectedCount} шт. Итого к выдаче: {FinalCount} шт.",
|
||||
originalCount, errorCount, replacedCount, injectedCount, resultsTasks.Count);
|
||||
"Трансформация пула задач (Rename). Исходных: {OriginalCount}. Отклонено (Error): {ErrorCount}. " +
|
||||
"Заменено на старые: {ReplacedCount}. Итого к выдаче: {FinalCount}",
|
||||
tasks.Count, errorCount, replacedCount, finalTasks.Count
|
||||
);
|
||||
|
||||
// Затем отсортируем по NextRun, чтоб ближайшие были выше
|
||||
return resultsTasks.OrderBy(t => t.NextRun).ToList();
|
||||
// Возвращаем без дополнительной сортировки по NextRun. Порядок сохранен начального списка
|
||||
return finalTasks;
|
||||
}
|
||||
|
||||
|
||||
@@ -353,9 +384,13 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
||||
/// <returns></returns>
|
||||
private async Task SetErrorStatusAsync(List<Guid> taskIds, string logMessage)
|
||||
{
|
||||
if (taskIds == null || taskIds.Count == 0)
|
||||
return;
|
||||
|
||||
var tasks = await _robotConfigurationRepository.Get()
|
||||
.Include(t => t.Template)
|
||||
.Where(t => taskIds.Contains(t.Id)).ToListAsync();
|
||||
.Where(t => taskIds.Contains(t.Id))
|
||||
.ToListAsync();
|
||||
|
||||
if (tasks.Count == 0)
|
||||
return;
|
||||
@@ -380,16 +415,19 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
||||
|
||||
await _robotHistoryRepository.CreateAsync(history);
|
||||
|
||||
_logger.LogInformation("Для целевого задания {TaskId}, по переименованию шаблона в {TemplateName}, установлен статус ошибки, так как связанное задание со старым шаблоном со статусом ошибка.", task.Id, task.Template!.Name);
|
||||
_logger.LogInformation("Для целевого задания {TaskId} (шаблон '{TemplateName}') установлен статус ошибки, " +
|
||||
"так как связанное задание со старым шаблоном не было успешно выполнено.",
|
||||
task.Id, task.Template!.Name);
|
||||
}
|
||||
|
||||
if (await _robotHistoryRepository.CommitAsync())
|
||||
{
|
||||
_logger.LogDebug("Установлен статус Ошибка, для заданий {TaskCount} шт.", tasks.Count);
|
||||
_logger.LogDebug("Установлен статус 'Ошибка', для заданий {TaskCount} шт.", tasks.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Ошибка при установке статуса задания Ошибка, для заданий {TaskCount} шт.", tasks.Count);
|
||||
_logger.LogError("Ошибка при установке статуса задания 'Ошибка', для заданий {TaskCount} шт. Транзакция отменена", tasks.Count);
|
||||
throw new DbErrorException("Не удалось сохранить изменения статусов заданий при обработке переименования шаблона.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,19 +569,19 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
||||
|
||||
if (!nextRun.HasValue)
|
||||
{
|
||||
_logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
|
||||
_logger.LogError("При обновлении nextRun для шаблона {TemplateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nextRun.Value < DateTimeOffset.UtcNow)
|
||||
{
|
||||
_logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun<Now [{nextRun}<{now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
|
||||
_logger.LogError("При обновлении nextRun для шаблона {TemplateId}, расчитанный nextRun<Now [{NextRun}<{Now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nextRun != template.NextRun)
|
||||
{
|
||||
_logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}");
|
||||
_logger.LogDebug("Для шаблона {TemplateId} обновляю nextRun. Новое: {NewNextRun}, старое: {OldNextRun}", template.Id, nextRun, template.NextRun);
|
||||
|
||||
template.LastRun = template.NextRun;
|
||||
template.NextRun = nextRun.Value;
|
||||
|
||||
@@ -15,13 +15,13 @@ namespace PARR.DAL.Repositories.Base
|
||||
{
|
||||
internal abstract class BaseRepository<T> : IBaseRepository<T> where T : class, IBaseEntity
|
||||
{
|
||||
protected readonly ILogger logger;
|
||||
protected readonly ILogger _logger;
|
||||
protected readonly DbSet<T> EntitySet;
|
||||
protected readonly DataContext EntityContext;
|
||||
|
||||
protected BaseRepository(ILogger logger, DataContext dataContext)
|
||||
{
|
||||
this.logger = logger;
|
||||
this._logger = logger;
|
||||
this.EntityContext = dataContext;
|
||||
this.EntitySet = dataContext.Set<T>();
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace PARR.DAL.Repositories.Base
|
||||
|
||||
public virtual async Task<bool> AddRangeAsync(List<T> objs)
|
||||
{
|
||||
logger.LogDebug("Начинаю добавление диапазона объектов типа {EntityType}, количество: {Count}",
|
||||
_logger.LogDebug("Начинаю добавление диапазона объектов типа {EntityType}, количество: {Count}",
|
||||
typeof(T).Name, objs.Count);
|
||||
|
||||
objs.ForEach(item => item.DateCreated = DateTimeOffset.UtcNow);
|
||||
@@ -37,26 +37,26 @@ namespace PARR.DAL.Repositories.Base
|
||||
try
|
||||
{
|
||||
await EntitySet.AddRangeAsync(objs);
|
||||
logger.LogDebug("Успешно добавлено {Count} объектов типа {EntityType}",
|
||||
_logger.LogDebug("Успешно добавлено {Count} объектов типа {EntityType}",
|
||||
objs.Count, typeof(T).Name);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Ошибка при добавлении диапазона объектов типа {EntityType}", typeof(T).Name);
|
||||
_logger.LogError(ex, "Ошибка при добавлении диапазона объектов типа {EntityType}", typeof(T).Name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> CommitAsync(IHistoryInitiator? initiator = null)
|
||||
{
|
||||
logger.LogDebug("Начинаю сохранение изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
||||
_logger.LogDebug("Начинаю сохранение изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
||||
|
||||
#region Изменения
|
||||
var modifiedEntrities = EntityContext.ChangeTracker.Entries()
|
||||
.Where(t => t.State == EntityState.Modified/* || t.State == EntityState.Deleted*/);
|
||||
|
||||
logger.LogDebug("Найдено {Count} измененных сущностей для обработки истории", modifiedEntrities.Count());
|
||||
_logger.LogDebug("Найдено {Count} измененных сущностей для обработки истории", modifiedEntrities.Count());
|
||||
|
||||
foreach (var obj in modifiedEntrities)
|
||||
{
|
||||
@@ -73,13 +73,13 @@ namespace PARR.DAL.Repositories.Base
|
||||
try
|
||||
{
|
||||
var changedCount = await EntityContext.SaveChangesAsync();
|
||||
logger.LogDebug("Успешно сохранено {ChangedCount} изменений в БД для объектов типа {EntityType}",
|
||||
_logger.LogDebug("Успешно сохранено {ChangedCount} изменений в БД для объектов типа {EntityType}",
|
||||
changedCount, typeof(T).Name);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Ошибка при сохранении изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
||||
_logger.LogError(ex, "Ошибка при сохранении изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -94,14 +94,14 @@ namespace PARR.DAL.Repositories.Base
|
||||
if (initiator == null)
|
||||
return;
|
||||
|
||||
logger.LogDebug("Устанавливаю инициатора для изменений");
|
||||
_logger.LogDebug("Устанавливаю инициатора для изменений");
|
||||
|
||||
// Задаем инициатора только для новых и измененных записей
|
||||
var entrities = EntityContext.ChangeTracker.Entries()
|
||||
.Where(t => t.State == EntityState.Modified || t.State == EntityState.Added);
|
||||
|
||||
var entityCount = entrities.Count();
|
||||
logger.LogDebug("Найдено {Count} сущностей для установки инициатора", entityCount);
|
||||
_logger.LogDebug("Найдено {Count} сущностей для установки инициатора", entityCount);
|
||||
|
||||
// смотрим есть ли у объекта интерфейс IHistoryInitiator, если есть, задаём значения
|
||||
foreach (var obj in entrities)
|
||||
@@ -113,7 +113,7 @@ namespace PARR.DAL.Repositories.Base
|
||||
(obj.Entity as IHistoryInitiator)!.InitiatorParrComponentId = initiator?.InitiatorParrComponentId ?? null;
|
||||
(obj.Entity as IHistoryInitiator)!.InitiatorComment = initiator?.InitiatorComment ?? null;
|
||||
|
||||
logger.LogDebug("Установлен инициатор для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
_logger.LogDebug("Установлен инициатор для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,12 +140,12 @@ namespace PARR.DAL.Repositories.Base
|
||||
|
||||
if (!isManual)
|
||||
{
|
||||
logger.LogDebug("Обновляю DateModified для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
_logger.LogDebug("Обновляю DateModified для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
entity.DateModified = DateTimeOffset.UtcNow;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogDebug("Пропуск обновления DateModified (ManualControl) для {EntityType}", entityType.Name);
|
||||
_logger.LogDebug("Пропуск обновления DateModified (ManualControl) для {EntityType}", entityType.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ namespace PARR.DAL.Repositories.Base
|
||||
/// <param name="obj"></param>
|
||||
private void TableHistoryResolver(EntityEntry obj)
|
||||
{
|
||||
logger.LogDebug("Проверяю необходимость создания истории для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
_logger.LogDebug("Проверяю необходимость создания истории для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
|
||||
var myHistoryInterface = obj.Entity.GetType().GetInterfaces()
|
||||
.Where(t => t.IsGenericType)
|
||||
@@ -166,7 +166,7 @@ namespace PARR.DAL.Repositories.Base
|
||||
// у этого объекта нет интерфейса IMyHistory<>. Не ведем историю
|
||||
if (myHistoryInterface == null)
|
||||
{
|
||||
logger.LogDebug("Сущность типа {EntityType} не требует ведения истории", obj.Entity.GetType().Name);
|
||||
_logger.LogDebug("Сущность типа {EntityType} не требует ведения истории", obj.Entity.GetType().Name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,13 +176,13 @@ namespace PARR.DAL.Repositories.Base
|
||||
var historyType = myHistoryInterface.GetGenericArguments().First();
|
||||
var historyProps = historyType.GetProperties(/*BindingFlags.DeclaredOnly | */ /*BindingFlags.Public*/).ToList();
|
||||
|
||||
logger.LogDebug("Создаю историю для сущности типа {EntityType}, тип истории: {HistoryType}",
|
||||
_logger.LogDebug("Создаю историю для сущности типа {EntityType}, тип истории: {HistoryType}",
|
||||
obj.Entity.GetType().Name, historyType.Name);
|
||||
|
||||
var historyInstance = Activator.CreateInstance(historyType);
|
||||
if (historyInstance == null)
|
||||
{
|
||||
logger.LogError("Не смог создать инстанс для ведения истории {HistoryType}", historyType.Name);
|
||||
_logger.LogError("Не смог создать инстанс для ведения истории {HistoryType}", historyType.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -198,11 +198,11 @@ namespace PARR.DAL.Repositories.Base
|
||||
try
|
||||
{
|
||||
EntityContext.Add(historyInstance);
|
||||
logger.LogDebug("История добавлена для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
_logger.LogDebug("История добавлена для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Ошибка при добавлении объекта в историю {HistoryType}", historyType.Name);
|
||||
_logger.LogError(ex, "Ошибка при добавлении объекта в историю {HistoryType}", historyType.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace PARR.DAL.Repositories.Base
|
||||
/// <param name="propsList"></param>
|
||||
private void FillHistoryProps(EntityEntry originalObj, ref object historyInstance, List<PropertyInfo> propsList)
|
||||
{
|
||||
logger.LogDebug("Заполняю историю для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
||||
_logger.LogDebug("Заполняю историю для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
||||
|
||||
foreach (var prop in propsList)
|
||||
{
|
||||
@@ -240,7 +240,7 @@ namespace PARR.DAL.Repositories.Base
|
||||
histProp.SetValue(historyInstance, origValues);
|
||||
}
|
||||
|
||||
logger.LogDebug("Завершено заполнение истории для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
||||
_logger.LogDebug("Завершено заполнение истории для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
||||
}
|
||||
|
||||
|
||||
@@ -256,14 +256,14 @@ namespace PARR.DAL.Repositories.Base
|
||||
var histProp = instanceObj.GetType().GetProperty(propName);
|
||||
if (histProp == null)
|
||||
{
|
||||
logger.LogError("При изменении объекта для БД, не найдено свойство {PropertyName}", propName);
|
||||
_logger.LogError("При изменении объекта для БД, не найдено свойство {PropertyName}", propName);
|
||||
return;
|
||||
}
|
||||
|
||||
// сравним типы
|
||||
if (histProp.PropertyType != typeof(TValue))
|
||||
{
|
||||
logger.LogError("При изменении объекта для БД, не совпадают типы у свойства {PropertyName}, {PropertyType}!={ValueType}",
|
||||
_logger.LogError("При изменении объекта для БД, не совпадают типы у свойства {PropertyName}, {PropertyType}!={ValueType}",
|
||||
propName, histProp.PropertyType.Name, typeof(TValue).Name);
|
||||
return;
|
||||
}
|
||||
@@ -330,7 +330,7 @@ namespace PARR.DAL.Repositories.Base
|
||||
|
||||
public virtual async Task<bool> CreateAsync(T obj)
|
||||
{
|
||||
logger.LogDebug("Начинаю создание объекта типа {EntityType}", typeof(T).Name);
|
||||
_logger.LogDebug("Начинаю создание объекта типа {EntityType}", typeof(T).Name);
|
||||
|
||||
if (obj.DateCreated == DateTimeOffset.MinValue)
|
||||
obj.DateCreated = DateTimeOffset.UtcNow;
|
||||
@@ -338,73 +338,73 @@ namespace PARR.DAL.Repositories.Base
|
||||
try
|
||||
{
|
||||
await EntitySet.AddAsync(obj);
|
||||
logger.LogDebug("Объект типа {EntityType} добавлен в контекст", typeof(T).Name);
|
||||
_logger.LogDebug("Объект типа {EntityType} добавлен в контекст", typeof(T).Name);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Ошибка при добавлении объекта типа {EntityType} в БД", typeof(T).Name);
|
||||
_logger.LogError(ex, "Ошибка при добавлении объекта типа {EntityType} в БД", typeof(T).Name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Delete(T obj)
|
||||
{
|
||||
logger.LogDebug("Начинаю удаление объекта типа {EntityType}", obj.GetType().Name);
|
||||
_logger.LogDebug("Начинаю удаление объекта типа {EntityType}", obj.GetType().Name);
|
||||
|
||||
try
|
||||
{
|
||||
EntitySet.Remove(obj);
|
||||
logger.LogDebug("Объект типа {EntityType} удален из контекста", obj.GetType().Name);
|
||||
_logger.LogDebug("Объект типа {EntityType} удален из контекста", obj.GetType().Name);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД", obj.GetType().Name);
|
||||
_logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД", obj.GetType().Name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<bool> DeleteAsync(Guid id)
|
||||
{
|
||||
logger.LogDebug("Начинаю удаление объекта типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
||||
_logger.LogDebug("Начинаю удаление объекта типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
||||
|
||||
try
|
||||
{
|
||||
var exist = await GetAsync(id);
|
||||
if (exist == null)
|
||||
{
|
||||
logger.LogError("Ошибка при удалении из БД. Не найдена запись в БД типа {EntityType} с id: {Id}",
|
||||
_logger.LogError("Ошибка при удалении из БД. Не найдена запись в БД типа {EntityType} с id: {Id}",
|
||||
typeof(T).Name, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
EntitySet.Remove(exist);
|
||||
logger.LogDebug("Объект типа {EntityType} с ID {Id} удален из контекста", typeof(T).Name, id);
|
||||
_logger.LogDebug("Объект типа {EntityType} с ID {Id} удален из контекста", typeof(T).Name, id);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД по ID: {Id}", typeof(T).Name, id);
|
||||
_logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД по ID: {Id}", typeof(T).Name, id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IQueryable<T> Get()
|
||||
{
|
||||
logger.LogDebug("Получаю набор объектов типа {EntityType}", typeof(T).Name);
|
||||
_logger.LogDebug("Получаю набор объектов типа {EntityType}", typeof(T).Name);
|
||||
return EntitySet;
|
||||
}
|
||||
|
||||
public virtual async Task<T?> GetAsync(Guid id)
|
||||
{
|
||||
logger.LogDebug("Получаю объект типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
||||
_logger.LogDebug("Получаю объект типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
||||
return await EntitySet.FirstOrDefaultAsync(t => t.Id == id);
|
||||
}
|
||||
|
||||
public virtual IQueryable<T> GetPage(IQueryable<T> query, PaginationFilter paginationFilter)
|
||||
{
|
||||
logger.LogDebug("Получаю страницу объектов типа {EntityType}, страница: {PageNumber}, размер: {PageSize}",
|
||||
_logger.LogDebug("Получаю страницу объектов типа {EntityType}, страница: {PageNumber}, размер: {PageSize}",
|
||||
typeof(T).Name, paginationFilter.PageNumber, paginationFilter.PageSize);
|
||||
|
||||
int skip = (paginationFilter.PageNumber - 1) * paginationFilter.PageSize;
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace PARR.DAL.Repositories
|
||||
? ((TaskStatusEnum)taskStatusValue).ToString()
|
||||
: $"Unknown ({taskStatusValue})";
|
||||
|
||||
logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как текущий статус {currentStatus}",
|
||||
_logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как текущий статус {currentStatus}",
|
||||
updatingStatus, configuration.Id, configuration.TemplateId, taskStatusName);
|
||||
return false;
|
||||
}
|
||||
@@ -65,13 +65,13 @@ namespace PARR.DAL.Repositories
|
||||
// есть ли связь у config с templetes, может инклуда нет, мало ли
|
||||
if (configuration.Template == null)
|
||||
{
|
||||
logger.LogWarning("При изменении статуса задания на обновление шаблона, не смог проверить наличае ScheduleEsppId, так как нет Include с Templates. Пропустил эту проверку. configurationId: {configurationId}", configuration.Id);
|
||||
_logger.LogWarning("При изменении статуса задания на обновление шаблона, не смог проверить наличае ScheduleEsppId, так как нет Include с Templates. Пропустил эту проверку. configurationId: {configurationId}", configuration.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (configuration.Template.ScheduleEsppId == null)
|
||||
{
|
||||
logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как у шаблона отсутсвтует ScheduleEsppId=null",
|
||||
_logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как у шаблона отсутсвтует ScheduleEsppId=null",
|
||||
updatingStatus, configuration.Id, configuration.TemplateId);
|
||||
return false;
|
||||
}
|
||||
@@ -80,7 +80,7 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
// Статус ОК, можно ставить Updating
|
||||
ChangeTaskStatus(updatingStatus, configuration);
|
||||
logger.LogInformation("Установлен статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}", updatingStatus, configuration.Id, configuration.TemplateId);
|
||||
_logger.LogInformation("Установлен статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}", updatingStatus, configuration.Id, configuration.TemplateId);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -154,7 +154,7 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
logger.LogError($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
|
||||
_logger.LogError($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
|
||||
throw new Exception($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
|
||||
}
|
||||
|
||||
@@ -170,60 +170,72 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
var endDate = DateTimeOffset.UtcNow.Add(-robotWaitTime);
|
||||
|
||||
var configObjs = await EntitySet.Where(t =>
|
||||
var expiredConfigs = await EntitySet.Where(t =>
|
||||
t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
||||
&& t.AttemptsNumber >= robotAttemptsNumber
|
||||
&& t.LastRobotStatusUpdated <= endDate
|
||||
).ToListAsync();
|
||||
|
||||
if (!configObjs.Any())
|
||||
if (!expiredConfigs.Any())
|
||||
return;
|
||||
|
||||
configObjs.ForEach(item =>
|
||||
foreach (var item in expiredConfigs)
|
||||
{
|
||||
ChangeRobotStatus(RobotStatusEnum.Error, item);
|
||||
logger.LogInformation($"Устанавливаю RobotStatus: {RobotStatusEnum.Error} для RobotConfigurationId {item.Id}");
|
||||
});
|
||||
_logger.LogInformation("Устанавливаю статус RobotStatus: {RobotStatus} для RobotConfigurationId: {RobotConfigurationId}", RobotStatusEnum.Error, item.Id);
|
||||
}
|
||||
|
||||
#region Ищем, есть ли связанные шаблоны, которые должны переименоваться, им тоже нужно установить статус ошибки, но только для Шаблонов
|
||||
|
||||
var linksCount = 0;
|
||||
// Проактивная обработка связанных шаблонов переименования Old->New
|
||||
// Если старый шаблон умен, мы должны сразу убить (!!!замочить!!!) и новый (целевой), чтобы он не висел вечно в ожидании.
|
||||
|
||||
var templateIds = configObjs.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder).Select(t => t.TemplateId).ToList();
|
||||
if (templateIds.Any())
|
||||
var expiredTemplateIds = expiredConfigs
|
||||
.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder)
|
||||
.Select(t => t.TemplateId)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
if (expiredTemplateIds.Any())
|
||||
{
|
||||
// По этим именам находим целевые шаблоны, берем их задания, и ставим им статус Ошибка + записать в лог робота
|
||||
var configs = await EntitySet
|
||||
.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder
|
||||
&& t.RobotStatusCode != (int)RobotStatusEnum.Error
|
||||
&& EntityContext.Templates.Any(tmpl =>
|
||||
templateIds.Contains(tmpl.Id)
|
||||
&& tmpl.TemplateRenamePending != null
|
||||
&& tmpl.TemplateRenamePending.OldName == t.Template!.Name))
|
||||
.ToListAsync();
|
||||
// Находим OldName для этих шаблонов из таблицы переименований.
|
||||
var oldNamesToFail = await EntityContext.Templates
|
||||
.Where(t => expiredTemplateIds.Contains(t.Id) && t.TemplateRenamePending != null)
|
||||
.Select(t => t.TemplateRenamePending!.OldName)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
linksCount = configs.Count;
|
||||
|
||||
foreach (var item in configs)
|
||||
// Находим целевые (новые задачи), имена которых совпадают с найденными OldName
|
||||
if (oldNamesToFail.Any())
|
||||
{
|
||||
SetErrorRobotStatusAndMaxAttempts(item);
|
||||
var targetConfigs = await EntitySet
|
||||
.Where(t =>
|
||||
t.RobotCode == (int)RobotsEnum.TemplateOrder
|
||||
&& t.RobotStatusCode != (int)RobotStatusEnum.Error // Не трогаем те, что уже в ошибке
|
||||
&& oldNamesToFail.Contains(t.Template!.Name)
|
||||
).ToListAsync();
|
||||
|
||||
// Пишем в лог роботу
|
||||
var history = new RobotHistory
|
||||
foreach (var item in targetConfigs)
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
HistoryLevel = (int)RobotStatusEnum.Error,
|
||||
TaskStatusCode = item.TaskStatusCode,
|
||||
RobotConfigurationId = item.Id,
|
||||
RobotIp = null,
|
||||
RobotId = ParrComponentsEnum.Api.ToString(),
|
||||
RobotMessage = "[RobotConfigurationRepository] Установлен статус ошибки, так как не переименован связанный шаблон"
|
||||
};
|
||||
SetErrorRobotStatusAndMaxAttempts(item);
|
||||
|
||||
// Синхронный Add работает быстрее и безопаснее внутри цикла
|
||||
EntityContext.RobotHistories.Add(history);
|
||||
// Пишем в лог роботу
|
||||
var history = new RobotHistory
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
HistoryLevel = (int)RobotStatusEnum.Error,
|
||||
TaskStatusCode = item.TaskStatusCode,
|
||||
RobotConfigurationId = item.Id,
|
||||
RobotIp = null,
|
||||
RobotId = ParrComponentsEnum.Api.ToString(),
|
||||
RobotMessage = "[RobotConfigurationRepository] Установлен статус ошибки, так как не переименован связанный шаблон"
|
||||
};
|
||||
|
||||
logger.LogInformation($"Устанавливаю RobotStatus: {RobotStatusEnum.Error} для RobotConfigurationId {item.Id}");
|
||||
// Синхронный Add работает быстрее и безопаснее внутри цикла
|
||||
EntityContext.RobotHistories.Add(history);
|
||||
|
||||
_logger.LogInformation("Проактивно установлен статус {Status} для целевого задания RobotConfigurationID: {Id} из-за ошибки старого шаблона.", RobotStatusEnum.Error, item.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -231,7 +243,7 @@ namespace PARR.DAL.Repositories
|
||||
var result = await CommitAsync();
|
||||
|
||||
if (!result)
|
||||
logger.LogError("Ошибка при сохранении изменений RobotStatus для просроченных заданий в количестве {Count} шт.", configObjs.Count + linksCount);
|
||||
_logger.LogError("Ошибка при сохранении изменений RobotStatus для просроченных заданий. Откат транзакции.");
|
||||
//else
|
||||
// logger.LogInformation("Успешно обработано и переведено в статус Ошибки просроченных заданий: {Count} шт.", configObjs.Count + linksCount);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
public async Task<Template?> GetTemplateByNameAsync(string name)
|
||||
{
|
||||
logger.LogDebug("Поиск шаблона по имени: {TemplateName}", name);
|
||||
_logger.LogDebug("Поиск шаблона по имени: {TemplateName}", name);
|
||||
|
||||
var template = await GetWithIncludes()
|
||||
.Include(t => t.RobotConfigurations)
|
||||
@@ -24,11 +24,11 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
if (template != null)
|
||||
{
|
||||
logger.LogDebug("Шаблон найден: {TemplateId}, имя: {TemplateName}", template.Id, template.Name);
|
||||
_logger.LogDebug("Шаблон найден: {TemplateId}, имя: {TemplateName}", template.Id, template.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogDebug("Шаблон с именем {TemplateName} не найден", name);
|
||||
_logger.LogDebug("Шаблон с именем {TemplateName} не найден", name);
|
||||
}
|
||||
|
||||
return template;
|
||||
@@ -36,7 +36,7 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
public IQueryable<Template> GetWithIncludes()
|
||||
{
|
||||
logger.LogDebug("Получаю шаблоны с include связями");
|
||||
_logger.LogDebug("Получаю шаблоны с include связями");
|
||||
|
||||
return Get()
|
||||
.Include(h => h.Unit)
|
||||
@@ -60,7 +60,7 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
public override Task<bool> CreateAsync(Template obj)
|
||||
{
|
||||
logger.LogDebug("Создание шаблона: {TemplateName}", obj.Name);
|
||||
_logger.LogDebug("Создание шаблона: {TemplateName}", obj.Name);
|
||||
|
||||
// добавление роботов для шаблона
|
||||
obj.RobotConfigurations = new List<RobotConfiguration>
|
||||
@@ -91,7 +91,7 @@ namespace PARR.DAL.Repositories
|
||||
}
|
||||
};
|
||||
|
||||
logger.LogDebug("Добавлены роботы для шаблона {TemplateName}", obj.Name);
|
||||
_logger.LogDebug("Добавлены роботы для шаблона {TemplateName}", obj.Name);
|
||||
|
||||
return base.CreateAsync(obj);
|
||||
}
|
||||
@@ -99,7 +99,7 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
public async Task<Guid?> ReserveUnusedTemplateAsync(Guid newUnitId, HistoryInitiator initiator)
|
||||
{
|
||||
logger.LogDebug("Резервирую неиспользуемый шаблон с проверкой конфигураций роботов для UnitId: {UnitId}", newUnitId);
|
||||
_logger.LogDebug("Резервирую неиспользуемый шаблон с проверкой конфигураций роботов для UnitId: {UnitId}", newUnitId);
|
||||
|
||||
var sql = @"
|
||||
UPDATE ""Templates""
|
||||
@@ -163,19 +163,19 @@ namespace PARR.DAL.Repositories
|
||||
|
||||
if (reservedTemplateId != Guid.Empty)
|
||||
{
|
||||
logger.LogInformation("Успешно зарезервирован шаблон с ID: {TemplateId} для UnitId: {UnitId}",
|
||||
_logger.LogInformation("Успешно зарезервирован шаблон с ID: {TemplateId} для UnitId: {UnitId}",
|
||||
reservedTemplateId, newUnitId);
|
||||
return reservedTemplateId;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId} (не найдено подходящих конфигураций роботов)", newUnitId);
|
||||
_logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId} (не найдено подходящих конфигураций роботов)", newUnitId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Ошибка при резервировании шаблона для UnitId: {UnitId}", newUnitId);
|
||||
_logger.LogError(ex, "Ошибка при резервировании шаблона для UnitId: {UnitId}", newUnitId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace PARR.DAL.Repositories
|
||||
var exist = await GetAsync(id);
|
||||
if (exist == null)
|
||||
{
|
||||
logger.LogError($"Ошибка при удалении из БД. Не найдена запись в БД с id: {id}");
|
||||
_logger.LogError($"Ошибка при удалении из БД. Не найдена запись в БД с id: {id}");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user