feat(api,core): Задания роботам на обновление расписаний, выдается с периодом охлаждения, если последнее изменение было NextRunWorker или EsppScheduleWorker и значение lastRun+ период охлаждения, меньше чем сейчас.

This commit is contained in:
Mikhail Trubnikov
2026-07-10 14:11:16 +10:00
parent 33cdc29e80
commit 33b0576ccc
8 changed files with 79 additions and 467 deletions

View File

@@ -52,7 +52,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
public async Task<RobotTaskTemplate> GetTemplateTaskAsync(TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId)
{
var templateTask = await GetTaskAsync(RobotsEnum.TemplateOrder, taskStatusCode, acquireTask, robotIp, robotId);
var templateTask = await GetTaskAsync(RobotsEnum.TemplateOrder, taskStatusCode, acquireTask, robotIp, robotId, TimeSpan.Zero);
var task = mapper.Map<RobotTaskTemplate>(templateTask);
@@ -72,9 +72,9 @@ namespace PARR.Core.Services.RobotTask.Implementations
}
public async Task<RobotTaskSchedule> GetScheduleTaskAsync(TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, IHistoryInitiator historyInitiator)
public async Task<RobotTaskSchedule> GetScheduleTaskAsync(TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, IHistoryInitiator historyInitiator, TimeSpan scheduleCooldownDuration)
{
var scheduleTask = await GetTaskAsync(RobotsEnum.ScheduleOrder, taskStatusCode, acquireTask, robotIp, robotId);
var scheduleTask = await GetTaskAsync(RobotsEnum.ScheduleOrder, taskStatusCode, acquireTask, robotIp, robotId, scheduleCooldownDuration);
// Проверяем nextRun, lastRun, обновляем их
@@ -121,14 +121,14 @@ namespace PARR.Core.Services.RobotTask.Implementations
/// <param name="robotIp"></param>
/// <returns></returns>
/// <exception cref="NotFoundException"></exception>
private async Task<RobotConfiguration> GetTaskAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId)
private async Task<RobotConfiguration> GetTaskAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, TimeSpan scheduleCooldownDuration)
{
// 1. Ищем все задания с превышенным кол-вом попыток и просроченным временем, ставим им статус ошибки
await robotConfigurationRepository.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);
// 2. Ищем доступные задания
var availableTasks = await GetAvailableTasksAsync(robotCode, taskStatusCode);
var availableTasks = await GetAvailableTasksAsync(robotCode, taskStatusCode, scheduleCooldownDuration);
if (availableTasks.Count == 0)
throw new NotFoundException("Нет доступных заданий для робота");
@@ -137,7 +137,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
if (acquireTask)
{
// Берем задание в работу, устанавливаем ей статус "В работе"
// Берем задание в работу, устанавливаем ему статус "В работе"
acquiredTaskId = await AcquireTaskAsync(availableTasks, robotIp, robotId);
if (acquiredTaskId == null)
@@ -165,21 +165,35 @@ namespace PARR.Core.Services.RobotTask.Implementations
/// <param name="robotCode"></param>
/// <param name="taskStatusCode"></param>
/// <returns></returns>
private async Task<List<Guid>> GetAvailableTasksAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode)
private async Task<List<Guid>> GetAvailableTasksAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, TimeSpan scheduleCooldownDuration)
{
var query = robotConfigurationRepository.Get()
.AsNoTracking()
.Where(t => t.RobotCode == (int)robotCode && t.TaskStatusCode == (int)taskStatusCode);
.Where(t => t.RobotCode == (int)robotCode/* && t.TaskStatusCode == (int)taskStatusCode*/);
// Если это задание для робота расписаний
if (robotCode == RobotsEnum.ScheduleOrder)
{
// Выбираем только записи с созданными шаблонами (у которых статус 30), а только потом ищем у них расписания
var createdTemplates = robotConfigurationRepository.Get()
.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder && t.TaskStatusCode == (int)TaskStatusEnum.Ok)
.Select(t => t.TemplateId);
#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));
query = query.Where(t => createdTemplates.Contains(t.TemplateId));
// Не берем шаблоны, у которых lastRun + 3 часа < сейчас, и у них последний инициатор был или nextRun (10) или esppSchedule (5), это условие применяется только к активированным расписаниям
var cooldownThreshold = DateTimeOffset.UtcNow.Add(-scheduleCooldownDuration);
query = query.Where(t =>
// Условие кулдауна: проверяем, попадает ли шаблон под ЗАПРЕТ
!(
t.Template!.IsActiveSchedule
&& (t.Template.InitiatorParrComponentId == ParrComponentsEnum.EsppScheduleSync || t.Template.InitiatorParrComponentId == ParrComponentsEnum.NextRun)
&& t.Template.LastRun >= cooldownThreshold
)
);
}
// Сортируем по nextRun, чтобы те, у кого nextRun ближе к текущей, выполнились скорее
@@ -189,7 +203,14 @@ namespace PARR.Core.Services.RobotTask.Implementations
var tasks = new List<Guid>();
// Ещем первые 10 заданий в статусе ОЖИДАНИЕ
tasks = await query.Where(t => t.RobotStatusCode == (int)RobotStatusEnum.Wait).Take(TakeTasks).Select(t => t.Id).ToListAsync();
tasks = await query
.Where(t =>
t.RobotStatusCode == (int)RobotStatusEnum.Wait
&& t.TaskStatusCode == (int)taskStatusCode
).Take(TakeTasks)
.Select(t => t.Id)
.ToListAsync();
logger.LogDebug("Найдено заданий в статусе 'Ожидание' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());