2026-07-22 16:02:04 +10:00
using InfluxDB.Client.Api.Domain ;
using Microsoft.EntityFrameworkCore ;
2023-10-05 12:28:31 +10:00
using Microsoft.Extensions.Logging ;
2026-04-30 10:35:31 +10:00
using PARR.Core.Repositories.Interfaces ;
2023-10-05 12:28:31 +10:00
using PARR.DAL.Context ;
2026-04-14 09:56:31 +10:00
using PARR.DAL.Repositories.Base ;
2026-04-30 10:35:31 +10:00
using PARR.Domain.Entities ;
2026-07-22 16:02:04 +10:00
using PARR.Domain.Entities.RobotEntities ;
2026-04-13 16:58:30 +10:00
using PARR.Domain.Enums ;
2026-05-27 08:19:20 +10:00
using PARR.Domain.Settings ;
2023-10-05 12:28:31 +10:00
2026-04-30 10:35:31 +10:00
namespace PARR.DAL.Repositories
2023-10-05 12:28:31 +10:00
{
2026-04-30 10:35:31 +10:00
internal class RobotConfigurationRepository : BaseRepository < RobotConfiguration > , IRobotConfigurationRepository
2023-10-05 12:28:31 +10:00
{
2026-05-27 08:19:20 +10:00
private readonly SettingsFromDb settingsFromDb ;
public RobotConfigurationRepository ( DataContext dataContext , ILogger < RobotConfigurationRepository > logger , SettingsFromDb settingsFromDb ) : base ( logger , dataContext )
{
this . settingsFromDb = settingsFromDb ;
}
2023-10-05 16:56:02 +10:00
2025-12-09 12:20:27 +10:00
public void ChangeTaskStatus ( TaskStatusEnum taskStatus , RobotConfiguration configuration )
2023-10-05 16:56:02 +10:00
{
configuration . TaskStatusCode = ( int ) taskStatus ;
switch ( taskStatus )
{
case TaskStatusEnum . Creating :
2025-12-09 12:20:27 +10:00
ChangeRobotStatus ( RobotStatusEnum . Wait , configuration ) ;
2023-10-05 16:56:02 +10:00
break ;
case TaskStatusEnum . Updating :
2025-12-09 12:20:27 +10:00
ChangeRobotStatus ( RobotStatusEnum . Wait , configuration ) ;
2023-10-05 16:56:02 +10:00
break ;
case TaskStatusEnum . Ok :
2025-12-09 12:20:27 +10:00
ChangeRobotStatus ( RobotStatusEnum . Complete , configuration ) ;
2023-10-05 16:56:02 +10:00
break ;
default :
break ;
}
2026-03-06 15:10:30 +10:00
}
2023-10-05 16:56:02 +10:00
2026-03-06 15:10:30 +10:00
public bool SetUpdateTaskStatusIfAllow ( RobotConfiguration configuration )
{
var updatingStatus = TaskStatusEnum . Updating ;
// ставить статус Updating можно только если текущий статус == Ok
if ( configuration . TaskStatusCode ! = ( int ) TaskStatusEnum . Ok )
{
2026-03-18 17:51:54 +10:00
int taskStatusValue = configuration . TaskStatusCode ;
string taskStatusName = Enum . IsDefined ( typeof ( TaskStatusEnum ) , taskStatusValue )
? ( ( TaskStatusEnum ) taskStatusValue ) . ToString ( )
: $"Unknown ({taskStatusValue})" ;
2026-03-11 12:10:11 +10:00
logger . LogInformation ( "Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как текущий статус {currentStatus}" ,
2026-03-27 11:58:03 +10:00
updatingStatus , configuration . Id , configuration . TemplateId , taskStatusName ) ;
2026-03-06 15:10:30 +10:00
return false ;
}
2026-03-13 10:22:13 +10:00
// Если хотим поставить Updating у шаблона, можно ставить только в том случае, если у шаблона уже есть ScheduleEsppId
if ( configuration . RobotCode = = ( int ) RobotsEnum . TemplateOrder )
{
// есть ли связь у config с templetes, может инклуда нет, мало ли
if ( configuration . Template = = null )
{
logger . LogWarning ( "При изменении статуса задания на обновление шаблона, не смог проверить наличае ScheduleEsppId, так как нет Include с Templates. Пропустил эту проверку. configurationId: {configurationId}" , configuration . Id ) ;
}
else
{
if ( configuration . Template . ScheduleEsppId = = null )
{
logger . LogInformation ( "Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как у шаблона отсутсвтует ScheduleEsppId=null" ,
updatingStatus , configuration . Id , configuration . TemplateId ) ;
return false ;
}
}
}
2026-03-06 15:10:30 +10:00
// Статус О К , можно ставить Updating
ChangeTaskStatus ( updatingStatus , configuration ) ;
2026-03-11 12:10:11 +10:00
logger . LogInformation ( "Установлен статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}" , updatingStatus , configuration . Id , configuration . TemplateId ) ;
2026-03-06 15:10:30 +10:00
return true ;
2023-10-05 16:56:02 +10:00
}
2026-03-06 15:10:30 +10:00
2025-12-09 12:20:27 +10:00
public void ChangeRobotStatus ( RobotStatusEnum robotStatus , RobotConfiguration configuration )
2023-10-05 16:56:02 +10:00
{
configuration . RobotStatusCode = ( int ) robotStatus ;
switch ( robotStatus )
{
case RobotStatusEnum . InProgress :
configuration . AttemptsNumber + + ;
2023-10-06 11:38:33 +10:00
configuration . LastRobotStatusUpdated = DateTimeOffset . UtcNow ;
2023-10-05 16:56:02 +10:00
break ;
2026-07-22 16:02:04 +10:00
case RobotStatusEnum . Error :
break ;
2023-10-05 16:56:02 +10:00
case RobotStatusEnum . Complete :
2023-10-06 11:38:33 +10:00
configuration . LastRobotStatusUpdated = DateTimeOffset . UtcNow ;
2023-10-05 16:56:02 +10:00
break ;
case RobotStatusEnum . Wait :
2023-10-06 11:38:33 +10:00
configuration . LastRobotStatusUpdated = null ;
2023-10-05 16:56:02 +10:00
configuration . AttemptsNumber = 0 ;
break ;
default :
break ;
}
}
2026-07-22 16:02:04 +10:00
public void SetErrorRobotStatusAndMaxAttempts ( RobotConfiguration configuration )
{
ChangeRobotStatus ( RobotStatusEnum . Error , configuration ) ;
configuration . AttemptsNumber = settingsFromDb . RobotAttemptsNumber ;
configuration . LastRobotStatusUpdated = DateTimeOffset . UtcNow ;
}
2026-05-25 16:59:42 +10:00
public async Task < bool > SetInProgressStatusAsync ( Guid id )
{
// Если задание все еще в статусе Wait (RobotStatusEnum.Wait), установить ему статус "InProgress"
2026-05-27 08:19:20 +10:00
var endDate = DateTimeOffset . UtcNow . Add ( - settingsFromDb . RobotWaitTime ) ;
2026-05-25 16:59:42 +10:00
// Выполняем атомарный UPDATE напрямую в базе данных
2026-07-13 16:16:37 +10:00
var affectedRows = await EntitySet . Where ( t = > t . Id = = id
2026-05-27 08:19:20 +10:00
& & (
// Задания в статусе ожидание
t . RobotStatusCode = = ( int ) RobotStatusEnum . Wait
| | (
2026-07-13 16:16:37 +10:00
// Задание в статусе в работе, но они зависли
2026-05-27 08:19:20 +10:00
t . RobotStatusCode = = ( int ) RobotStatusEnum . InProgress
& & t . AttemptsNumber < settingsFromDb . RobotAttemptsNumber
& & t . LastRobotStatusUpdated < endDate
)
)
)
2026-05-25 16:59:42 +10:00
. ExecuteUpdateAsync ( s = > s
. SetProperty ( t = > t . RobotStatusCode , ( int ) RobotStatusEnum . InProgress )
. SetProperty ( t = > t . LastRobotStatusUpdated , DateTimeOffset . UtcNow )
2026-07-13 16:16:37 +10:00
. SetProperty ( t = > t . AttemptsNumber , t = > t . AttemptsNumber + 1 )
2026-05-25 16:59:42 +10:00
) ;
return affectedRows > 0 ;
}
2025-11-26 14:34:03 +10:00
public RobotConfiguration GetFromTemplateByRobotCode ( RobotsEnum robotsEnum , Template template )
2023-10-05 16:56:02 +10:00
{
var config = template . RobotConfigurations . FirstOrDefault ( t = > t . RobotCode = = ( int ) robotsEnum ) ;
if ( config = = null )
{
logger . LogError ( $"У шаблона нет конфигурации роботов. TemplateId: {template.Id}" ) ;
throw new Exception ( $"У шаблона нет конфигурации роботов. TemplateId: {template.Id}" ) ;
}
return config ;
}
// Поиск невыполненных заданий и установка им статуса ошибки робота
2026-05-25 16:59:42 +10:00
public async Task MarkExpiredTasksAsFailedAsync ( int robotAttemptsNumber , TimeSpan robotWaitTime )
2023-10-05 16:56:02 +10:00
{
//Ищем `RobotStatusCode` = 22 и `LastStatusUpdated` истекло и `AttemptsNumber` >= допустимого значения из настроек,
//ставим всем этим записям `RobotStatusCode`= 33
var endDate = DateTimeOffset . UtcNow . Add ( - robotWaitTime ) ;
var configObjs = await EntitySet . Where ( t = >
t . RobotStatusCode = = ( int ) RobotStatusEnum . InProgress
& & t . AttemptsNumber > = robotAttemptsNumber
2023-10-06 11:38:33 +10:00
& & t . LastRobotStatusUpdated < = endDate
2023-10-05 16:56:02 +10:00
) . ToListAsync ( ) ;
if ( ! configObjs . Any ( ) )
return ;
configObjs . ForEach ( item = >
{
2025-12-09 12:20:27 +10:00
ChangeRobotStatus ( RobotStatusEnum . Error , item ) ;
2023-10-05 16:56:02 +10:00
logger . LogInformation ( $"Устанавливаю RobotStatus: {RobotStatusEnum.Error} для RobotConfigurationId {item.Id}" ) ;
} ) ;
2026-07-22 16:02:04 +10:00
#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
2023-10-05 16:56:02 +10:00
var result = await CommitAsync ( ) ;
if ( ! result )
2026-07-22 16:02:04 +10:00
logger . LogError ( "Ошибка при сохранении изменений RobotStatus для просроченных заданий в количестве {Count} шт." , configObjs . Count + linksCount ) ;
//else
// logger.LogInformation("Успешно обработано и переведено в статус Ошибки просроченных заданий: {Count} шт.", configObjs.Count + linksCount);
2023-10-05 16:56:02 +10:00
}
2023-10-05 12:28:31 +10:00
}
}