diff --git a/PARR.Core/Repositories/Interfaces/IRobotConfigurationRepository.cs b/PARR.Core/Repositories/Interfaces/IRobotConfigurationRepository.cs
index 5bc2d65a..0160ee45 100644
--- a/PARR.Core/Repositories/Interfaces/IRobotConfigurationRepository.cs
+++ b/PARR.Core/Repositories/Interfaces/IRobotConfigurationRepository.cs
@@ -49,5 +49,11 @@ namespace PARR.Core.Repositories.Interfaces
///
///
Task SetInProgressStatusAsync(Guid id);
+
+ ///
+ /// Установить статус робота - Ошибка, и поставить максимальное значение попыток
+ ///
+ ///
+ void SetErrorRobotStatusAndMaxAttempts(RobotConfiguration configuration);
}
}
diff --git a/PARR.Core/Services/RobotTask/Implementations/RobotTaskService.cs b/PARR.Core/Services/RobotTask/Implementations/RobotTaskService.cs
index a10536b5..3757b276 100644
--- a/PARR.Core/Services/RobotTask/Implementations/RobotTaskService.cs
+++ b/PARR.Core/Services/RobotTask/Implementations/RobotTaskService.cs
@@ -1,11 +1,15 @@
using AutoMapper;
+using InfluxDB.Client.Api.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.BLL.Helpers;
using PARR.Core.Repositories.Interfaces;
+using PARR.Core.Repositories.Interfaces.TemplateRepositories;
using PARR.Core.Services.NextRunServices;
using PARR.Core.Services.RobotTask.Interfaces;
+using PARR.Core.Services.RobotTask.Models;
using PARR.Core.Services.Shortcodes;
+using PARR.Domain.Common.Template;
using PARR.Domain.DTOs.RobotTask;
using PARR.Domain.Entities;
using PARR.Domain.Entities.Base.History;
@@ -20,16 +24,18 @@ namespace PARR.Core.Services.RobotTask.Implementations
{
///
/// Количество заданий которые рассматриваем для взятия в работу.
+ /// Рекомендованное значение, кол-во роботов * 3
///
- private readonly int TakeTasks = 10;
+ private readonly int TakeTasks = 15 * 3;
- private readonly ILogger logger;
- private readonly IRobotConfigurationRepository robotConfigurationRepository;
- private readonly SettingsFromDb settingsFromDb;
- private readonly IRobotHistoryRepository robotHistoryRepository;
- private readonly IMapper mapper;
- private readonly IShortcodesService shortcodesService;
- private readonly INextRunService nextRunService;
+ private readonly ILogger _logger;
+ private readonly IRobotConfigurationRepository _robotConfigurationRepository;
+ private readonly SettingsFromDb _settingsFromDb;
+ private readonly IRobotHistoryRepository _robotHistoryRepository;
+ private readonly IMapper _mapper;
+ private readonly IShortcodesService _shortcodesService;
+ private readonly INextRunService _nextRunService;
+ private readonly ITemplateRenamePendingRepository _templateRenamePendingRepository;
public RobotTaskService(
ILogger logger,
@@ -38,16 +44,18 @@ namespace PARR.Core.Services.RobotTask.Implementations
IRobotHistoryRepository robotHistoryRepository,
IMapper mapper,
IShortcodesService shortcodesService,
- INextRunService nextRunService
+ INextRunService nextRunService,
+ ITemplateRenamePendingRepository templateRenamePendingRepository
)
{
- this.logger = logger;
- this.robotConfigurationRepository = robotConfigurationRepository;
- this.settingsFromDb = settingsFromDb;
- this.robotHistoryRepository = robotHistoryRepository;
- this.mapper = mapper;
- this.shortcodesService = shortcodesService;
- this.nextRunService = nextRunService;
+ this._logger = logger;
+ this._robotConfigurationRepository = robotConfigurationRepository;
+ this._settingsFromDb = settingsFromDb;
+ this._robotHistoryRepository = robotHistoryRepository;
+ this._mapper = mapper;
+ this._shortcodesService = shortcodesService;
+ this._nextRunService = nextRunService;
+ _templateRenamePendingRepository = templateRenamePendingRepository;
}
@@ -55,19 +63,19 @@ namespace PARR.Core.Services.RobotTask.Implementations
{
var templateTask = await GetTaskAsync(RobotsEnum.TemplateOrder, taskStatusCode, acquireTask, robotIp, robotId, TimeSpan.Zero);
- var task = mapper.Map(templateTask);
+ var task = _mapper.Map(templateTask);
- task = task with { FullDescription = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(task.FullDescription, templateTask.Template!)) };
- task = task with { ShortDescription = await shortcodesService.ApplyShortcodesAsync(task.ShortDescription, templateTask.Template!) };
- task = task with { Solution = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(task.Solution, templateTask.Template!)) };
- task = task with { TnkName = await shortcodesService.ApplyShortcodesAsync(task.TnkName, templateTask.Template!) };
- task = task with { WorkName = await shortcodesService.ApplyShortcodesAsync(task.WorkName, templateTask.Template!) };
- task = task with { WorkGroup = await shortcodesService.ApplyShortcodesAsync(task.WorkGroup, templateTask.Template!) };
- task = task with { ResponseArea = await shortcodesService.ApplyShortcodesAsync(task.ResponseArea, templateTask.Template!) };
+ task = task with { FullDescription = NormalizeLineEndingsToCrlf(await _shortcodesService.ApplyShortcodesAsync(task.FullDescription, templateTask.Template!)) };
+ task = task with { ShortDescription = await _shortcodesService.ApplyShortcodesAsync(task.ShortDescription, templateTask.Template!) };
+ task = task with { Solution = NormalizeLineEndingsToCrlf(await _shortcodesService.ApplyShortcodesAsync(task.Solution, templateTask.Template!)) };
+ task = task with { TnkName = await _shortcodesService.ApplyShortcodesAsync(task.TnkName, templateTask.Template!) };
+ task = task with { WorkName = await _shortcodesService.ApplyShortcodesAsync(task.WorkName, templateTask.Template!) };
+ task = task with { WorkGroup = await _shortcodesService.ApplyShortcodesAsync(task.WorkGroup, templateTask.Template!) };
+ task = task with { ResponseArea = await _shortcodesService.ApplyShortcodesAsync(task.ResponseArea, templateTask.Template!) };
- task = task with { ClosingCode = settingsFromDb.ClosingCode };
- task = task with { Initiator = settingsFromDb.Initiator };
- task = task with { Category = settingsFromDb.Category };
+ task = task with { ClosingCode = _settingsFromDb.ClosingCode };
+ task = task with { Initiator = _settingsFromDb.Initiator };
+ task = task with { Category = _settingsFromDb.Category };
return task;
}
@@ -82,22 +90,22 @@ namespace PARR.Core.Services.RobotTask.Implementations
var resultUpdateNextRun = await UpdateNextRunAsync(scheduleTask, historyInitiator);
if (!resultUpdateNextRun)
{
- logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", scheduleTask.TemplateId);
+ _logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", scheduleTask.TemplateId);
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
}
- var task = mapper.Map(scheduleTask);
+ var task = _mapper.Map(scheduleTask);
- task = task with { Timezone = settingsFromDb.EsppScheduleTimezone };
- task = task with { WorkGroup = await shortcodesService.ApplyShortcodesAsync(task.WorkGroup, scheduleTask.Template!) };
- task = task with { ResponseArea = await shortcodesService.ApplyShortcodesAsync(task.ResponseArea, scheduleTask.Template!) };
+ task = task with { Timezone = _settingsFromDb.EsppScheduleTimezone };
+ task = task with { WorkGroup = await _shortcodesService.ApplyShortcodesAsync(task.WorkGroup, scheduleTask.Template!) };
+ task = task with { ResponseArea = await _shortcodesService.ApplyShortcodesAsync(task.ResponseArea, scheduleTask.Template!) };
//nextRun в часовой зоне УЗ Робота ЕСПП
- var nextRunWithRobotTz = scheduleTask.Template!.NextRun.Add(nextRunService.GetEsppAccountOffset());
+ var nextRunWithRobotTz = scheduleTask.Template!.NextRun.Add(_nextRunService.GetEsppAccountOffset());
//на всякий случай еще раз проверяем, что дата не устарела и отправляем задание
if (nextRunWithRobotTz < DateTimeOffset.UtcNow)
{
- logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
+ _logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
task.TemplateId, nextRunWithRobotTz, DateTimeOffset.UtcNow);
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
}
@@ -105,7 +113,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
task = task with { NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithRobotTz) };
task = task with { GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithRobotTz) };
- task = task with { RepeatRange = settingsFromDb.ScheduleRepeatRange };
+ task = task with { RepeatRange = _settingsFromDb.ScheduleRepeatRange };
task = task with { };
return task;
@@ -125,7 +133,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
private async Task GetTaskAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, TimeSpan scheduleCooldownDuration)
{
// 1. Ищем все задания с превышенным кол-вом попыток и просроченным временем, ставим им статус ошибки
- await robotConfigurationRepository.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);
+ await _robotConfigurationRepository.MarkExpiredTasksAsFailedAsync(_settingsFromDb.RobotAttemptsNumber, _settingsFromDb.RobotWaitTime);
// 2. Ищем доступные задания
@@ -148,7 +156,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
{
// Берем первую задачу из списка доступных
acquiredTaskId = availableTasks.First();
- logger.LogDebug("Задача не требует захвата, взята первая из доступных: {TaskId}", acquiredTaskId);
+ _logger.LogDebug("Задача не требует захвата, взята первая из доступных: {TaskId}", acquiredTaskId);
}
@@ -168,20 +176,14 @@ namespace PARR.Core.Services.RobotTask.Implementations
///
private async Task> GetAvailableTasksAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, TimeSpan scheduleCooldownDuration)
{
- var query = robotConfigurationRepository.Get()
+ var query = _robotConfigurationRepository.Get()
.AsNoTracking()
- .Where(t => t.RobotCode == (int)robotCode/* && t.TaskStatusCode == (int)taskStatusCode*/);
+ .Where(t => t.RobotCode == (int)robotCode);
// Если это задание для робота расписаний
if (robotCode == RobotsEnum.ScheduleOrder)
{
// Выбираем только записи с созданными шаблонами (у которых статус 30), а только потом ищем у них расписания
- #region Старый не оптимизированный запрос
- //var createdTemplates = robotConfigurationRepository.Get()
- // .Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder && t.TaskStatusCode == (int)TaskStatusEnum.Ok)
- // .Select(t => t.TemplateId);
- //query = query.Where(t => createdTemplates.Contains(t.TemplateId));
- #endregion
query = query.Where(t => t.Template!.RobotConfigurations.Any(x => x.RobotCode == (int)RobotsEnum.TemplateOrder && x.TaskStatusCode == (int)TaskStatusEnum.Ok));
@@ -200,20 +202,22 @@ namespace PARR.Core.Services.RobotTask.Implementations
// Сортируем по nextRun, чтобы те, у кого nextRun ближе к текущей, выполнились скорее
query = query.OrderBy(t => t.Template!.NextRun).ThenBy(t => t.Template!.IsActiveSchedule).ThenBy(t => t.Template!.IsActiveTemplate);
- // Кандидаты заданий
- var tasks = new List();
+ // Кандидаты заданий, Id задания и имя шаблона
+ //var tasks = new List();
+ var tasks = new List();
- // Ещем первые 10 заданий в статусе ОЖИДАНИЕ
+ // Ищем первые TakeTasks заданий в статусе ОЖИДАНИЕ
tasks = await query
.Where(t =>
t.RobotStatusCode == (int)RobotStatusEnum.Wait
&& t.TaskStatusCode == (int)taskStatusCode
).Take(TakeTasks)
- .Select(t => t.Id)
+ //.Select(t => t.Id)
+ .Select(t => new RobotTaskDetails(t.Id, t.Template!.Name, t.Template.NextRun))
.ToListAsync();
- logger.LogDebug("Найдено заданий в статусе 'Ожидание' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
+ _logger.LogDebug("Найдено заданий в статусе 'Ожидание' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
if (tasks.Count == 0)
{
@@ -222,20 +226,171 @@ namespace PARR.Core.Services.RobotTask.Implementations
// Далее проверяется `LastStatusUpdated`, что время последнего смены статуса не превышает допустимого(берется из настроек, поле `RobotWaitTime`)
// и что текущая попытка не больше разрешенной(берется из настроек, поле `RobotAttemptsNumber`) - если это так, берется эта запись.
- var endDate = DateTimeOffset.UtcNow.Add(-settingsFromDb.RobotWaitTime);
+ var endDate = DateTimeOffset.UtcNow.Add(-_settingsFromDb.RobotWaitTime);
tasks = await query.Where(t => t.RobotStatusCode == (int)RobotStatusEnum.InProgress
- && t.TaskStatusCode==(int)taskStatusCode
- && t.AttemptsNumber < settingsFromDb.RobotAttemptsNumber
+ && t.TaskStatusCode == (int)taskStatusCode
+ && t.AttemptsNumber < _settingsFromDb.RobotAttemptsNumber
&& t.LastRobotStatusUpdated < endDate)
.Take(TakeTasks)
- .Select(t => t.Id)
+ //.Select(t => t.Id)
+ .Select(t => new RobotTaskDetails(t.Id, t.Template!.Name, t.Template.NextRun))
.ToListAsync();
- logger.LogDebug("Найдено заданий в статусе 'В работе' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
+ _logger.LogDebug("Найдено заданий в статусе 'В работе' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
}
- return tasks;
+ if (robotCode == RobotsEnum.TemplateOrder)
+ {
+ // Если запрашиваем шаблоны, смотрим корректируем список заданий в зависимости от статуса переименования.
+ // Это не относится к расписаниям, потому что у переименованных расписаний статус Updating, а оно не возьмется в работу, пока не обновится шаблон
+ tasks = await ReplaceTemplateTasksForRenameAsync(tasks, robotCode);
+ }
+
+ return tasks.Select(t => t.TaskId).ToList();
+ }
+
+
+ ///
+ /// Проверяет наличие шаблонов в процессе переименования и заменяет обычные задания на задания по переименованию.
+ /// Если связанный шаблон не переименован, и у него статус ошибки, целевому шаблону устанавливается статус ошибки.
+ ///
+ ///
+ ///
+ private async Task> ReplaceTemplateTasksForRenameAsync(List tasks, RobotsEnum robotCode)
+ {
+ if (tasks.Count == 0 || robotCode != RobotsEnum.TemplateOrder)
+ return tasks;
+
+
+ // Ищем есть ли связанные шаблоны с таким имененм на переименование
+ var taskTemplateNames = tasks.Select(t => t.TemplateName);
+ var templatesToRename = await _templateRenamePendingRepository.Get().AsNoTracking()
+ .Where(t => taskTemplateNames.Contains(t.OldName))
+ .ToListAsync();
+
+ _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()
+ .Include(t => t.Template)
+ .Where(t =>
+ t.RobotCode == (int)robotCode
+ && renameTemplateIds.Contains(t.TemplateId)
+ // Это может быть только обновление. Так как переименования для создаваемого шаблона быть не может
+ && t.TaskStatusCode == (int)TaskStatusEnum.Updating
+ ).ToListAsync();
+
+ // Ищем связанные задания которые в ошибке, и ставим целевому шаблону задание в ошибку
+ var errorTasks = renameTasks.Where(t => t.RobotStatusCode == (int)RobotStatusEnum.Error && t.AttemptsNumber >= _settingsFromDb.RobotAttemptsNumber).ToList();
+
+ var tasksToSetErrorStatus = new List();
+ if (errorTasks.Count > 0)
+ {
+ _logger.LogDebug("Найдено связанных заданий на переименование с ошибками: {ErrorCount}. Будем целевым шаблонам тоже ставить статус ошибки.", errorTasks.Count);
+
+ var errorTemplateNames = errorTasks.Select(t => t.Template!.Name).ToList();
+ // Берем целевые таски, находим в них задания которым надо поставить ошибку
+ tasksToSetErrorStatus = tasks.Where(t => errorTemplateNames.Contains(t.TemplateName)).Select(t => t.TaskId).ToList();
+
+ // Устанавливаем ошибку целевым + пишем комментарий от робота + нажимаем комит
+ var logMessage = "[RobotTaskService] Установлен статус ошибки, так как не переименован связанный шаблон";
+ await SetErrorStatusAsync(tasksToSetErrorStatus, logMessage);
+ }
+
+ var endDate = DateTimeOffset.UtcNow.Add(-_settingsFromDb.RobotWaitTime);
+ // Смотрим статусы роботов, можно взять в работу, только если (RobotStatus == Wait) или (InpRogress но которые еще не просрочены)
+ var allowedTasks = renameTasks.Where(t =>
+ t.RobotStatusCode == (int)RobotStatusEnum.Wait
+ || (t.RobotStatusCode == (int)RobotStatusEnum.InProgress && t.AttemptsNumber < _settingsFromDb.RobotAttemptsNumber && t.LastRobotStatusUpdated < endDate)
+ );
+
+ // Формируем список заданий
+
+ var originalCount = tasks.Count; // Запоминаем сколько было изначально
+
+ // Из исходных тасков удалить те которым установлен статус ошибки
+ var filteredOriginalTasks = tasks.Where(t => !tasksToSetErrorStatus.Contains(t.TaskId)).ToList();
+ var errorCount = tasksToSetErrorStatus.Count; // Столько ушло в ошибку
+
+ // Определяем, какие имена шаблонов мы БУДЕМ подменять на задачи переименования
+ var allowedRenameTemplateNames = allowedTasks.Select(t => t.Template!.Name).ToList();
+
+ // Из исходных удаляем те, которые мы сейчас заменим (подменим)
+ var resultsTasks = filteredOriginalTasks.Where(t => !allowedRenameTemplateNames.Contains(t.TemplateName)).ToList();
+
+ // Считаем сколько именно задач мы ВЫКИНУЛИ из исходного списка ради подмены
+ 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);
+
+ // Затем отсортируем по NextRun, чтоб ближайшие были выше
+ return resultsTasks.OrderBy(t => t.NextRun).ToList();
+ }
+
+
+ ///
+ /// Установить статус задания - ошибка
+ ///
+ ///
+ ///
+ private async Task SetErrorStatusAsync(List taskIds, string logMessage)
+ {
+ var tasks = await _robotConfigurationRepository.Get()
+ .Include(t => t.Template)
+ .Where(t => taskIds.Contains(t.Id)).ToListAsync();
+
+ if (tasks.Count == 0)
+ return;
+
+ foreach (var task in tasks)
+ {
+ // Так как это целевой шаблон, то ставим ему сразу максимальное кол-во попыток и ошибку, чтоб больше он не выдавался в заданиях, пока не исправим связанный
+ // Устанавливаем статус ошибки
+ _robotConfigurationRepository.SetErrorRobotStatusAndMaxAttempts(task);
+
+ // Пишем в лог роботу
+ var history = new RobotHistory
+ {
+ Id = Guid.NewGuid(),
+ HistoryLevel = (int)RobotStatusEnum.Error,
+ TaskStatusCode = task.TaskStatusCode,
+ RobotConfigurationId = task.Id,
+ RobotIp = null,
+ RobotId = ParrComponentsEnum.Api.ToString(),
+ RobotMessage = logMessage
+ };
+
+ await _robotHistoryRepository.CreateAsync(history);
+
+ _logger.LogInformation("Для целевого задания {TaskId}, по переименованию шаблона в {TemplateName}, установлен статус ошибки, так как связанное задание со старым шаблоном со статусом ошибка.", task.Id, task.Template!.Name);
+ }
+
+ if (await _robotHistoryRepository.CommitAsync())
+ {
+ _logger.LogDebug("Установлен статус Ошибка, для заданий {TaskCount} шт.", tasks.Count);
+ }
+ else
+ {
+ _logger.LogError("Ошибка при установке статуса задания Ошибка, для заданий {TaskCount} шт.", tasks.Count);
+ }
}
@@ -248,12 +403,12 @@ namespace PARR.Core.Services.RobotTask.Implementations
{
foreach (var taskId in tasks)
{
- var isChangedStatus = await robotConfigurationRepository.SetInProgressStatusAsync(taskId);
+ var isChangedStatus = await _robotConfigurationRepository.SetInProgressStatusAsync(taskId);
if (isChangedStatus)
{
- logger.LogDebug("Захвачена задача {TaskId}", taskId);
+ _logger.LogDebug("Захвачена задача {TaskId}", taskId);
- var task = await robotConfigurationRepository.Get()
+ var task = await _robotConfigurationRepository.Get()
.AsNoTracking()
.FirstAsync(t => t.Id == taskId);
@@ -268,18 +423,18 @@ namespace PARR.Core.Services.RobotTask.Implementations
RobotId = robotId
};
- if (!await robotHistoryRepository.CreateAsync(history) || !await robotHistoryRepository.CommitAsync())
+ if (!await _robotHistoryRepository.CreateAsync(history) || !await _robotHistoryRepository.CommitAsync())
throw new DbErrorException("Ошибка при добавлении истории робота, при взятии задания в работу.");
return taskId;
}
else
{
- logger.LogDebug("Не удалось захватить задачу {TaskId}", taskId);
+ _logger.LogDebug("Не удалось захватить задачу {TaskId}", taskId);
}
}
- logger.LogDebug("Не удалось захватить ни одну из доступных задач для робота");
+ _logger.LogDebug("Не удалось захватить ни одну из доступных задач для робота");
return null;
}
@@ -293,7 +448,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
///
private async Task GetTaskWithAllDataAsync(Guid taskId, RobotsEnum robotCode)
{
- IQueryable query = robotConfigurationRepository.Get()
+ IQueryable query = _robotConfigurationRepository.Get()
//.AsNoTracking() // нужно обязательно трекать, так как может измениться nextRun и его нужно будет сохранить
.AsSingleQuery()
// Общие инклуды для шаблонов и расписаний
@@ -372,23 +527,23 @@ namespace PARR.Core.Services.RobotTask.Implementations
var template = task.Template!;
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
- var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
+ var nextRun = await _nextRunService.GetNextRunForTemplateAsync(template.Id, false);
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
+ /// Модель задания для робота
+ ///
+ ///
+ ///
+ internal record RobotTaskDetails(Guid TaskId, string TemplateName, DateTimeOffset NextRun);
+}
diff --git a/PARR.DAL/Repositories/RobotConfigurationRepository.cs b/PARR.DAL/Repositories/RobotConfigurationRepository.cs
index efbb22be..ba4909ed 100644
--- a/PARR.DAL/Repositories/RobotConfigurationRepository.cs
+++ b/PARR.DAL/Repositories/RobotConfigurationRepository.cs
@@ -1,9 +1,11 @@
-using Microsoft.EntityFrameworkCore;
+using InfluxDB.Client.Api.Domain;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Core.Repositories.Interfaces;
using PARR.DAL.Context;
using PARR.DAL.Repositories.Base;
using PARR.Domain.Entities;
+using PARR.Domain.Entities.RobotEntities;
using PARR.Domain.Enums;
using PARR.Domain.Settings;
@@ -94,8 +96,8 @@ namespace PARR.DAL.Repositories
configuration.AttemptsNumber++;
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
break;
- //case RobotStatusEnum.Error:
- // break;
+ case RobotStatusEnum.Error:
+ break;
case RobotStatusEnum.Complete:
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
break;
@@ -108,6 +110,14 @@ namespace PARR.DAL.Repositories
}
}
+ public void SetErrorRobotStatusAndMaxAttempts(RobotConfiguration configuration)
+ {
+ ChangeRobotStatus(RobotStatusEnum.Error, configuration);
+
+ configuration.AttemptsNumber = settingsFromDb.RobotAttemptsNumber;
+ configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
+ }
+
public async Task SetInProgressStatusAsync(Guid id)
{
@@ -175,10 +185,55 @@ namespace PARR.DAL.Repositories
logger.LogInformation($"Устанавливаю RobotStatus: {RobotStatusEnum.Error} для RobotConfigurationId {item.Id}");
});
+ #region Ищем, есть ли связанные шаблоны, которые должны переименоваться, им тоже нужно установить статус ошибки, но только для Шаблонов
+
+ var linksCount = 0;
+
+ var templateIds = configObjs.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder).Select(t => t.TemplateId).ToList();
+ if (templateIds.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();
+
+ linksCount = configs.Count;
+
+ foreach (var item in configs)
+ {
+ SetErrorRobotStatusAndMaxAttempts(item);
+
+ // Пишем в лог роботу
+ 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] Установлен статус ошибки, так как не переименован связанный шаблон"
+ };
+
+ // Синхронный Add работает быстрее и безопаснее внутри цикла
+ EntityContext.RobotHistories.Add(history);
+
+ logger.LogInformation($"Устанавливаю RobotStatus: {RobotStatusEnum.Error} для RobotConfigurationId {item.Id}");
+ }
+ }
+ #endregion
+
var result = await CommitAsync();
if (!result)
- logger.LogError($"Ошибка при сохранении изменений RobotStatus для RobotConfigurationId: item.Id, RobotStatus: {RobotStatusEnum.Error}");
+ logger.LogError("Ошибка при сохранении изменений RobotStatus для просроченных заданий в количестве {Count} шт.", configObjs.Count + linksCount);
+ //else
+ // logger.LogInformation("Успешно обработано и переведено в статус Ошибки просроченных заданий: {Count} шт.", configObjs.Count + linksCount);
}