feat(dal, esppSync, nextRun): При синхронизации расписаний и шаблонов, при расчете nextRun в NextRunWorker - установить задание на обновление объекта, можно только если объект в статусе Ок. NextRunWorker - рефакторинг.

This commit is contained in:
Mikhail Trubnikov
2026-03-11 12:10:11 +10:00
parent 8cfccd7671
commit b9d1f923b3
10 changed files with 359 additions and 175 deletions

View File

@@ -2,6 +2,7 @@
using Microsoft.Extensions.DependencyInjection;
using PARR.BLL;
using PARR.DAL;
using PARR.NextRun.Services;
using PARR.NextRun.Settings;
namespace PARR.NextRun
@@ -19,6 +20,7 @@ namespace PARR.NextRun
services.AddTransient<INextRunIntervalService, NextRunIntervalService>();
services.AddTransient<INextRunRabbitService, NextRunRabbitService>();
services.AddTransient<INextRunUpdateService, NextRunUpdateService>();
}

View File

@@ -1,12 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
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.Services;
using PARR.NextRun.Settings;
namespace PARR.NextRun
@@ -42,76 +39,89 @@ namespace PARR.NextRun
{
using (var scope = serviceProvider.CreateScope())
{
//var appInWorkService = scope.ServiceProvider.GetService<IApplicationsInWorkService>();
//var esppSchService = scope.ServiceProvider.GetService<IEsppScheduleTransformService>();
var templateService = scope.ServiceProvider.GetService<ITemplateService>();
var jobGroupService = scope.ServiceProvider.GetService<IJobGroupService>();
var nextRunService = scope.ServiceProvider.GetService<INextRunService>();
var nextRunUpdateService = scope.ServiceProvider.GetRequiredService<INextRunUpdateService>();
if (templateService == null || nextRunService == null || jobGroupService == null)
throw new Exception($"Не смог получить серивс {nameof(ITemplateService)} или {nameof(INextRunService)} или {nameof(IJobGroupService)}");
await nextRunUpdateService.UpdateNextRunForTemplatesAsync(
// фильтр, только просроченные шаблоны
query => query.Where(t => t.NextRun < DateTimeOffset.UtcNow),
() => new HistoryInitiator
{
InitiatorComment = "Обновлён NextRun (интервал)",
InitiatorParrComponentId = ParrComponentsEnum.NextRun
},
"Интервал"
);
await HandlerAsync(templateService, nextRunService, jobGroupService);
//var templateService = scope.ServiceProvider.GetRequiredService<ITemplateService>();
//var nextRunService = scope.ServiceProvider.GetRequiredService<INextRunService>();
//var robotConfigurationService = scope.ServiceProvider.GetRequiredService<IRobotConfigurationService>();
//await HandlerAsync(templateService, nextRunService, robotConfigurationService);
}
}, workerSettings.RepeatEvery);
}
/// <summary>
/// Рассчет следующей даты срабатываения
/// </summary>
/// <returns></returns>
private async Task HandlerAsync(ITemplateService templateService, INextRunService nextRunService, IJobGroupService jobGroupService)
{
logger.LogInformation("Начинаю обновлять NextRun по расписанию");
///// <summary>
///// Рассчет следующей даты срабатываения
///// </summary>
///// <returns></returns>
//private async Task HandlerAsync(ITemplateService templateService, INextRunService nextRunService, IRobotConfigurationService robotConfigurationService)
//{
// logger.LogInformation("Начинаю обновлять NextRun по расписанию");
await UpdateNextRunAsync(templateService, nextRunService, jobGroupService);
// await UpdateNextRunAsync(templateService, nextRunService, robotConfigurationService);
logger.LogInformation($"Завершено обновление полей NextRun.");
}
// logger.LogInformation($"Завершено обновление полей NextRun.");
//}
private async Task UpdateNextRunAsync(ITemplateService templateService, INextRunService nextRunService, IJobGroupService jobGroupService)
{
// выбираем все шаблоны с просроченным nextRun в статусе Used
//private async Task UpdateNextRunAsync(ITemplateService templateService, INextRunService nextRunService, IRobotConfigurationService robotConfigurationService)
//{
// // выбираем все шаблоны с просроченным nextRun в статусе Used
var templatesForUpdate = await templateService.Get()
.Where(t =>
t.StatusTypeId == TemplateStatusTypeEnum.Used
&& t.NextRun < DateTimeOffset.UtcNow
).ToListAsync();
// var templatesForUpdate = await templateService.Get()
// .Include(t => t.RobotConfigurations)
// .Where(t =>
// t.StatusTypeId == TemplateStatusTypeEnum.Used
// && t.NextRun < DateTimeOffset.UtcNow
// ).ToListAsync();
logger.LogInformation("Найдено шаблонов в статусе Used с просроченным NextRun {count} шт.", templatesForUpdate.Count);
// logger.LogInformation("Найдено шаблонов в статусе Used с просроченным NextRun {count} шт.", templatesForUpdate.Count);
if (!templatesForUpdate.Any())
return;
// if (!templatesForUpdate.Any())
// return;
foreach (var template in templatesForUpdate)
{
var newNextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
// foreach (var template in templatesForUpdate)
// {
// var newNextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
if (newNextRun.HasValue)
{
template.LastRun = template.NextRun;
template.NextRun = newNextRun.Value;
}
else
{
logger.LogError("При расчете nextRun для шаблона {templateId}, '{templateName}', nextRun=null. Это значит что при расчете возникла ошибка.", template.Id, template.Name);
}
}
// if (newNextRun.HasValue)
// {
// template.LastRun = template.NextRun;
// template.NextRun = newNextRun.Value;
if (await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Обновлён NextRun", InitiatorParrComponentId = ParrComponentsEnum.NextRun }))
{
logger.LogInformation("Обновлены значения полей NextRun для шаблонов в статусе Used, {count} шт.", templatesForUpdate.Count);
}
else
{
logger.LogError("Ошибка при обновлении значений полей NextRun, для шаблонов в статусе Used, {count} шт.", templatesForUpdate.Count);
}
// //так как nextRun обновился, пробуем поставить задание на обновление
// var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, template);
// robotConfigurationService.SetUpdateTaskStatusIfAllow(config);
// }
// else
// {
// logger.LogError("При расчете nextRun для шаблона {templateId}, '{templateName}', nextRun=null. Это значит что при расчете возникла ошибка.", template.Id, template.Name);
// }
// }
}
// if (await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Обновлён NextRun", InitiatorParrComponentId = ParrComponentsEnum.NextRun }))
// {
// logger.LogInformation("Обновлены значения полей NextRun для шаблонов в статусе Used, {count} шт.", templatesForUpdate.Count);
// }
// else
// {
// logger.LogError("Ошибка при обновлении значений полей NextRun, для шаблонов в статусе Used, {count} шт.", templatesForUpdate.Count);
// }
//}

View File

@@ -3,11 +3,8 @@ 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.Services;
using PARR.NextRun.Settings;
namespace PARR.NextRun
@@ -61,17 +58,29 @@ namespace PARR.NextRun
{
logger.LogInformation("Получили запрос: {message}", msg);
var query = transformService.GetModelFromJson<NextRunUpdateMq>(msg);
if (query == null)
var queryMq = transformService.GetModelFromJson<NextRunUpdateMq>(msg);
if (queryMq == null)
return;
if (!await IsValidJobGroupAsync(query.JobGroupId))
if (!await IsValidJobGroupAsync(queryMq.JobGroupId))
{
logger.LogError("Не найдена группа работ с id: {jobGroupId}", query.JobGroupId);
logger.LogError("Не найдена группа работ с id: {jobGroupId}", queryMq.JobGroupId);
return;
}
await UpdateNextRunAsync(query);
using (var scope = serviceProvider.CreateScope())
{
var nextRunUpdateService = scope.ServiceProvider.GetRequiredService<INextRunUpdateService>();
await nextRunUpdateService.UpdateNextRunForTemplatesAsync(
// фильтр по JobGroupId
query => query.Where(t => t.Job!.GroupId == queryMq.JobGroupId),
() => queryMq.Initiator,
$"RabbitMq_JobGroupId_{queryMq.JobGroupId}"
);
}
//await UpdateNextRunAsync(query);
}
/// <summary>
@@ -90,74 +99,80 @@ namespace PARR.NextRun
}
/// <summary>
/// Обновить все NextRun в JobGroup
/// </summary>
/// <param name="jobGroupId"></param>
/// <returns></returns>
private async Task UpdateNextRunAsync(NextRunUpdateMq queryMq)
{
using var scope = serviceProvider.CreateScope();
///// <summary>
///// Обновить все NextRun в JobGroup
///// </summary>
///// <param name="jobGroupId"></param>
///// <returns></returns>
//private async Task UpdateNextRunAsync(NextRunUpdateMq queryMq)
//{
// using var scope = serviceProvider.CreateScope();
var templateService = scope.ServiceProvider.GetRequiredService<ITemplateService>();
var nextRunService = scope.ServiceProvider.GetRequiredService<INextRunService>();
// var templateService = scope.ServiceProvider.GetRequiredService<ITemplateService>();
// var nextRunService = scope.ServiceProvider.GetRequiredService<INextRunService>();
// var robotConfigurationService = scope.ServiceProvider.GetRequiredService<IRobotConfigurationService>();
// Берем шаблоны только в статусе Used
var templates = await templateService.Get()
.Where(t =>
t.Job!.GroupId == queryMq.JobGroupId
&& t.StatusTypeId == TemplateStatusTypeEnum.Used
).ToListAsync();
// // Берем шаблоны только в статусе Used
// var templates = await templateService.Get()
// .Include(t => t.RobotConfigurations)
// .Where(t =>
// t.Job!.GroupId == queryMq.JobGroupId
// && t.StatusTypeId == TemplateStatusTypeEnum.Used
// ).ToListAsync();
logger.LogInformation("Найдено шаблонов {count} шт. в статусе Used в группе работ {jobGroupId}", templates.Count, queryMq.JobGroupId);
// logger.LogInformation("Найдено шаблонов {count} шт. в статусе Used в группе работ {jobGroupId}", templates.Count, queryMq.JobGroupId);
if (!templates.Any())
return;
// if (!templates.Any())
// return;
var updatedTemplates = 0;
// var updatedTemplates = 0;
foreach (var template in templates)
{
var newNextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
// 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 (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);
// 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;
// template.LastRun = template.NextRun;
// template.NextRun = newNextRun.Value;
updatedTemplates++;
}
else
{
logger.LogDebug("Не требуется обновлять nextRun для шаблона {templateId}, {templateName}. Рассчитанный и исходный равны. NextRun: {NextRun}",
template.Id, template.Name, template.NextRun);
}
}
// //так как nextRun обновился, пробуем поставить задание на обновление
// var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, template);
// robotConfigurationService.SetUpdateTaskStatusIfAllow(config);
if (updatedTemplates > 0)
{
if (await templateService.CommitAsync(queryMq.Initiator))
{
logger.LogInformation("Успешно обновлены nextRun у {count} шаблонов, группа работ: {jobGroupId}", updatedTemplates, queryMq.JobGroupId);
}
else
{
logger.LogError("При сохранении nextRun для шаблонов {count} шт, произошла ошибка при сохранении в БД. JobGroupId: {jobGroupId}", updatedTemplates, queryMq.JobGroupId);
}
}
else
{
logger.LogInformation("Для группы работ {jobGroupId}, все nextRun актуальны. Нечего обновлять.", queryMq.JobGroupId);
}
}
// updatedTemplates++;
// }
// else
// {
// logger.LogDebug("Не требуется обновлять nextRun для шаблона {templateId}, {templateName}. Рассчитанный и исходный равны. NextRun: {NextRun}",
// template.Id, template.Name, template.NextRun);
// }
// }
// if (updatedTemplates > 0)
// {
// if (await templateService.CommitAsync(queryMq.Initiator))
// {
// logger.LogInformation("Успешно обновлены nextRun у {count} шаблонов, группа работ: {jobGroupId}", updatedTemplates, queryMq.JobGroupId);
// }
// else
// {
// logger.LogError("При сохранении nextRun для шаблонов {count} шт, произошла ошибка при сохранении в БД. JobGroupId: {jobGroupId}", updatedTemplates, queryMq.JobGroupId);
// }
// }
// else
// {
// logger.LogInformation("Для группы работ {jobGroupId}, все nextRun актуальны. Нечего обновлять.", queryMq.JobGroupId);
// }
//}
}
}

View File

@@ -0,0 +1,17 @@
using PARR.Common.Domain;
using PARR.DAL.Models;
namespace PARR.NextRun.Services
{
internal interface INextRunUpdateService
{
/// <summary>
/// Обновить NextRun для списка шаблонов
/// </summary>
/// <param name="filter">Фильтр выборки шаблонов</param>
/// <param name="getInitiator"></param>
/// <param name="operationName"></param>
/// <returns></returns>
Task UpdateNextRunForTemplatesAsync(Func<IQueryable<Template>, IQueryable<Template>> filter, Func<IHistoryInitiator> getInitiator, string operationName);
}
}

View File

@@ -0,0 +1,114 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.Common.Domain;
using PARR.Constants;
using PARR.DAL.Models;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces;
namespace PARR.NextRun.Services
{
internal class NextRunUpdateService : INextRunUpdateService
{
private readonly ILogger<NextRunUpdateService> logger;
private readonly ITemplateService templateService;
private readonly INextRunService nextRunService;
private readonly IRobotConfigurationService robotConfigurationService;
public NextRunUpdateService(
ILogger<NextRunUpdateService> logger,
ITemplateService templateService,
INextRunService nextRunService,
IRobotConfigurationService robotConfigurationService
)
{
this.logger = logger;
this.templateService = templateService;
this.nextRunService = nextRunService;
this.robotConfigurationService = robotConfigurationService;
}
public async Task UpdateNextRunForTemplatesAsync(Func<IQueryable<Template>, IQueryable<Template>> filter, Func<IHistoryInitiator> getInitiator, string operationName)
{
var query = templateService.Get()
.Include(t => t.RobotConfigurations)
.Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Used);
var templates = await filter(query).ToListAsync();
logger.LogInformation("[{operationName}] Найдено шаблонов в статусе Used для обработки: {count}", operationName, templates.Count);
if (!templates.Any())
{
logger.LogInformation("[{operationName}] Шаблоны не найдены, выходим", operationName);
return;
}
var updatedCount = 0;
foreach (var template in templates)
{
var wasUpdated = await UpdateNextRunAsync(template);
if (wasUpdated)
updatedCount++;
}
if (updatedCount == 0)
{
logger.LogInformation("[{operationName}] Нет изменённых nextRun, сохранение не требуется", operationName);
return;
}
var initiator = getInitiator();
var commitResult = await templateService.CommitAsync(initiator);
if (commitResult)
logger.LogInformation("[{operationName}] Успешно обновлено {count} шаблонов", operationName, updatedCount);
else
logger.LogError("[{operationName}] Ошибка при сохранении {count} шаблонов в БД", operationName, updatedCount);
}
/// <summary>
/// Обновляет если надо nextRun для одного шаблона, если может, ставит задание на обновление
/// </summary>
/// <param name="template"></param>
/// <param name="nextRunService"></param>
/// <param name="robotConfigurationService"></param>
/// <param name="templateName"></param>
/// <param name="logger"></param>
/// <returns></returns>
private async Task<bool> UpdateNextRunAsync(Template template)
{
var newNextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
if (!newNextRun.HasValue)
{
logger.LogError("При расчете nextRun для шаблона {templateId}, '{templateName}' вернулся null. Это значит что при расчете возникла ошибка.", template.Id, template.Name);
return false;
}
if (template.NextRun == newNextRun.Value)
{
logger.LogDebug("NextRun для шаблона {templateId}, '{templateName}' не изменился: {nextRun}", template.Id, template.Name, newNextRun.Value);
return false;
}
logger.LogInformation("Обновление NextRun: шаблон {templateId}, '{templateName}'. Было: {oldNextRun}, стало: {newNextRun}", template.Id, template.Name, template.NextRun, newNextRun.Value);
template.LastRun = template.NextRun;
template.NextRun = newNextRun.Value;
//так как nextRun обновился, пробуем поставить задание на обновление
var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, template);
robotConfigurationService.SetUpdateTaskStatusIfAllow(config);
//шаблон изменен и нужен Commit
return true;
}
}
}