feat(nextRunWorker): добавлен еще один backgroundWorker, который смотрит очередь, и пересчитывает nextRun для jobGroupId

This commit is contained in:
Mikhail Trubnikov
2026-02-27 14:05:25 +10:00
parent f7a2170454
commit 10bf68709b
16 changed files with 319 additions and 33 deletions

View File

@@ -0,0 +1,163 @@
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;
}
await UpdateNextRunAsync(query.JobGroupId);
}
/// <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>
private async Task UpdateNextRunAsync(Guid jobGroupId)
{
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 =>
t.Job!.GroupId == jobGroupId
&& t.StatusTypeId == TemplateStatusTypeEnum.Used
).ToListAsync();
logger.LogInformation("Найдено шаблонов {count} шт. в статусе Used в группе работ {jobGroupId}", templates.Count, jobGroupId);
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)
{
if (await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Запрос из очереди на перерасчет всех nextRun для jobGroupId", InitiatorParrComponentId = ParrComponentsEnum.NextRun }))
{
logger.LogInformation("Успешно обновлены nextRun у {count} шаблонов, группа работ: {jobGroupId}", updatedTemplates, jobGroupId);
}
else
{
logger.LogError("При сохранении nextRun для шаблонов {count} шт, произошла ошибка при сохранении в БД. JobGroupId: {jobGroupId}", updatedTemplates, jobGroupId);
}
}
else
{
logger.LogInformation("Для группы работ {jobGroupId}, все nextRun актуальны. Нечего обновлять.", jobGroupId);
}
}
}
}