2026-02-27 14:05:25 +10:00
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.DependencyInjection ;
using Microsoft.Extensions.Logging ;
using PARR.BLL.Domain.Mq ;
using PARR.BLL.Services.Interfaces ;
using PARR.Common.Domain ;
using PARR.Constants ;
using PARR.DAL.NextRunServices ;
using PARR.DAL.Services.Interfaces ;
using PARR.DAL.Services.Interfaces.Job ;
using PARR.NextRun.Settings ;
namespace PARR.NextRun
{
/// <summary>
/// Расчет nextRun по заданию из очереди
/// </summary>
internal class NextRunRabbitService : INextRunRabbitService
{
private readonly ILogger < NextRunRabbitService > logger ;
private readonly IMqService mqService ;
private readonly WorkerSettings workerSettings ;
private readonly ITransformService transformService ;
private readonly IServiceProvider serviceProvider ;
public NextRunRabbitService (
ILogger < NextRunRabbitService > logger ,
IMqService mqService ,
WorkerSettings workerSettings ,
ITransformService transformService ,
IServiceProvider serviceProvider
)
{
this . logger = logger ;
this . mqService = mqService ;
this . workerSettings = workerSettings ;
this . transformService = transformService ;
this . serviceProvider = serviceProvider ;
}
public async Task StartAsync ( )
{
var isConnected = await mqService . InitConsumerAsync ( workerSettings . MqSettings ! , HandlerAsync ) ;
if ( ! isConnected )
throw new Exception ( "Ошибка при подключении к RabbitMq" ) ;
logger . LogInformation ( "Запущена проверка очереди {QueueName}." , workerSettings . MqSettings ! . QueueName ) ;
}
public async Task StopAsync ( )
{
await mqService . DisposeAsync ( ) ;
logger . LogInformation ( "Соединение с очередью {QueueName} закрыто" , workerSettings . MqSettings ! . QueueName ) ;
}
private async Task HandlerAsync ( string msg )
{
logger . LogInformation ( "Получили запрос: {message}" , msg ) ;
var query = transformService . GetModelFromJson < NextRunUpdateMq > ( msg ) ;
if ( query = = null )
return ;
if ( ! await IsValidJobGroupAsync ( query . JobGroupId ) )
{
logger . LogError ( "Н е найдена группа работ с id: {jobGroupId}" , query . JobGroupId ) ;
return ;
}
2026-02-27 16:37:52 +10:00
await UpdateNextRunAsync ( query ) ;
2026-02-27 14:05:25 +10:00
}
/// <summary>
/// Существует ли JobGroup с таким Id?
/// </summary>
/// <param name="jobGroupId"></param>
/// <returns></returns>
private async Task < bool > IsValidJobGroupAsync ( Guid jobGroupId )
{
using ( var scope = serviceProvider . CreateScope ( ) )
{
var jobGroupService = scope . ServiceProvider . GetRequiredService < IJobGroupService > ( ) ;
return await jobGroupService . Get ( ) . AnyAsync ( t = > t . Id = = jobGroupId ) ;
}
}
/// <summary>
/// Обновить все NextRun в JobGroup
/// </summary>
/// <param name="jobGroupId"></param>
/// <returns></returns>
2026-02-27 16:37:52 +10:00
private async Task UpdateNextRunAsync ( NextRunUpdateMq queryMq )
2026-02-27 14:05:25 +10:00
{
using var scope = serviceProvider . CreateScope ( ) ;
var templateService = scope . ServiceProvider . GetRequiredService < ITemplateService > ( ) ;
var nextRunService = scope . ServiceProvider . GetRequiredService < INextRunServiceV2 > ( ) ;
// Берем шаблоны только в статусе Used
var templates = await templateService . Get ( )
. Where ( t = >
2026-02-27 16:37:52 +10:00
t . Job ! . GroupId = = queryMq . JobGroupId
2026-02-27 14:05:25 +10:00
& & t . StatusTypeId = = TemplateStatusTypeEnum . Used
) . ToListAsync ( ) ;
2026-02-27 16:37:52 +10:00
logger . LogInformation ( "Найдено шаблонов {count} шт. в статусе Used в группе работ {jobGroupId}" , templates . Count , queryMq . JobGroupId ) ;
2026-02-27 14:05:25 +10:00
if ( ! templates . Any ( ) )
return ;
var updatedTemplates = 0 ;
foreach ( var template in templates )
{
var newNextRun = await nextRunService . GetNextRunForTemplateAsync ( template . Id , false ) ;
if ( newNextRun = = null )
{
logger . LogError ( "При расчете nextRun для шаблона {templateId}, {templateName} вернулся null" , template . Id , template . Name ) ;
continue ;
}
if ( template . NextRun ! = newNextRun )
{
logger . LogInformation ( "Обновлен nextRun для шаблона {templateId}, {templateName}, newNextRun: {newNextRun}, oldNextRun: {oldNextRun}" ,
template . Id , template . Name , newNextRun , template . NextRun ) ;
template . LastRun = template . NextRun ;
template . NextRun = newNextRun . Value ;
updatedTemplates + + ;
}
else
{
logger . LogDebug ( "Н е требуется обновлять nextRun для шаблона {templateId}, {templateName}. Рассчитанный и исходный равны. NextRun: {NextRun}" ,
template . Id , template . Name , template . NextRun ) ;
}
}
if ( updatedTemplates > 0 )
{
2026-02-27 16:37:52 +10:00
if ( await templateService . CommitAsync ( queryMq . Initiator ) )
2026-02-27 14:05:25 +10:00
{
2026-02-27 16:37:52 +10:00
logger . LogInformation ( "Успешно обновлены nextRun у {count} шаблонов, группа работ: {jobGroupId}" , updatedTemplates , queryMq . JobGroupId ) ;
2026-02-27 14:05:25 +10:00
}
else
{
2026-02-27 16:37:52 +10:00
logger . LogError ( "При сохранении nextRun для шаблонов {count} шт, произошла ошибка при сохранении в БД. JobGroupId: {jobGroupId}" , updatedTemplates , queryMq . JobGroupId ) ;
2026-02-27 14:05:25 +10:00
}
}
else
{
2026-02-27 16:37:52 +10:00
logger . LogInformation ( "Для группы работ {jobGroupId}, все nextRun актуальны. Нечего обновлять." , queryMq . JobGroupId ) ;
2026-02-27 14:05:25 +10:00
}
}
}
}