From a4f8e9eccc1d6235e5cb3caee96950fa503d142d Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Fri, 27 Feb 2026 16:37:52 +1000 Subject: [PATCH] =?UTF-8?q?feat(api,=20nextRun):=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B8=20=D1=80?= =?UTF-8?q?=D0=B0=D1=81=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B2?= =?UTF-8?q?=20jobGroup,=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D1=82=D1=81=D1=8F=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20nextRun=20=D0=B2=20=D1=81=D0=B2=D1=8F?= =?UTF-8?q?=D0=B7=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D1=88=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=D1=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PARR.API/Contracts/V1/ApiRoutes.cs | 7 ++ PARR.API/Controllers/V1/JobGroupController.cs | 74 +++++++++++++------ .../V1/JobGroupUpdateNextRunController.cs | 70 ++++++++++++++++++ PARR.API/Settings/MqSettings.cs | 10 +++ PARR.API/appsettings.Development.json | 3 + PARR.API/appsettings.json | 6 ++ PARR.BLL/Domain/Mq/NextRunUpdateMq.cs | 6 +- PARR.NextRun/NextRunRabbitService.cs | 16 ++-- PARR.NextRunWorker/RabbitWorker.cs | 2 +- 9 files changed, 162 insertions(+), 32 deletions(-) create mode 100644 PARR.API/Controllers/V1/JobGroupUpdateNextRunController.cs diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs index 9b13a272..48f6eae3 100644 --- a/PARR.API/Contracts/V1/ApiRoutes.cs +++ b/PARR.API/Contracts/V1/ApiRoutes.cs @@ -407,6 +407,13 @@ public const string getParam = "{id}"; } + public static class JobGroupUpdateNextRun + { + public const string UpdateNextRun = Base + "/job-groups/" + getParam + "/update-next-run"; + + public const string getParam = "{jobGroupId}"; + } + public static class JobGroupType { public const string GetAll = Base + "/job-group-types/"; diff --git a/PARR.API/Controllers/V1/JobGroupController.cs b/PARR.API/Controllers/V1/JobGroupController.cs index 532fd288..10b1cc44 100644 --- a/PARR.API/Controllers/V1/JobGroupController.cs +++ b/PARR.API/Controllers/V1/JobGroupController.cs @@ -11,14 +11,17 @@ using PARR.API.Contracts.V1.Responses.Base; using PARR.API.Controllers.V1.Base; using PARR.API.Extensions; using PARR.API.Services.Interfaces; +using PARR.API.Settings; +using PARR.BLL.Domain.Mq; using PARR.BLL.Helpers; +using PARR.BLL.Services.Interfaces; +using PARR.Common.Domain; using PARR.Constants; using PARR.DAL.Contracts; using PARR.DAL.DomainModels; using PARR.DAL.DomainServices.Interfaces; using PARR.DAL.Models; using PARR.DAL.Models.Job; -using PARR.DAL.NextRunServices; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Schedule; @@ -41,6 +44,8 @@ namespace PARR.API.Controllers.V1 private readonly IJobGroupTypeService jobGroupTypeService; private readonly IMatchingStatusService matchingStatusService; private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService; + private readonly IMqService mqService; + private readonly MqSettings mqSettings; public JobGroupController( ILogger logger, @@ -52,7 +57,9 @@ namespace PARR.API.Controllers.V1 IValidator validator, IJobGroupTypeService jobGroupTypeService, IMatchingStatusService matchingStatusService, - IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService + IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService, + IMqService mqService, + MqSettings mqSettings ) { this.logger = logger; @@ -65,6 +72,8 @@ namespace PARR.API.Controllers.V1 this.jobGroupTypeService = jobGroupTypeService; this.matchingStatusService = matchingStatusService; this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService; + this.mqService = mqService; + this.mqSettings = mqSettings; } @@ -248,7 +257,7 @@ namespace PARR.API.Controllers.V1 if (orig == null) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении группы заданий на выполнение работ. Не найдена группа с Id: {id}" } })); - // //Расписание было изменено, ниже добавим задание в очередь на обновление расписаний у связанных шаблонов + //Расписание было изменено, ниже добавим задание в очередь на обновление расписаний у связанных шаблонов var isScheduleChanged = IsScheduleChanged(orig, request); orig.GroupName = request.Name.Trim(); @@ -324,26 +333,25 @@ namespace PARR.API.Controllers.V1 $" {orig.Solution}, {orig.TemplateDuration}, {orig.ReferenceDate}, {orig.IsAutoDistributionEnabled}" + $", {orig.IsAgent}, {orig.AgentName}, {orig.AgentTimeOutSec}, {orig.AgentScript}"); - //TODO: Восстановить после перехода на JobGroup - //if (isScheduleChanged) - //{ - // //расписание было обновлено, отправим задание в очередь на перерасчет NextRun - // var requestToMq = new TemplateDistributorMq - // { - // ApplicationInWorkId = id - // }; - // var msg = JsonSerializer.Serialize(requestToMq); + #region расписание было изменено, отправим задание на перерасчет nextRun + if (isScheduleChanged) + { + // расписание было изменено, отправим задание на перерасчет nextRun + var requestToMq = new NextRunUpdateMq + { + JobGroupId = id, + Initiator = new HistoryInitiator { InitiatorComment = "Изменилось расписание группы работ в ГУИ, отправлен запрос на перерасчет nextRun", InitiatorParrComponentId = ParrComponentsEnum.Api } + }; + var sendResult = await mqService.SendAsync(mqSettings.NextRun, new List { requestToMq }); - // logger.LogDebug($"Расписание в РР applicationInWorkId: {id} было изменено. Отправляем задание в очередь на перерасчет NextRun"); + if (sendResult.IsSuccess) + logger.LogInformation("Задание на перерасчет NextRun успешно отправлено в очередь MQ {queueName}", mqSettings.NextRun.QueueName); + else + logger.LogError("Ошибка при отправке задания на перерасчет NextRun в очередь MQ {queueName}", mqSettings.NextRun.QueueName); + } + #endregion - // var sendResult = mqService.Send(mqSettings.TemplateDistributor, new[] { msg }); - - // if (sendResult.IsSuccess) - // logger.LogInformation($"Задание на перерасчет NextRun успешно отправлено в очередь MQ {mqSettings.TemplateDistributor.QueueName}"); - // else - // logger.LogError($"Ошибка при отправке задания на перерасчет NextRun в очередь MQ {mqSettings.TemplateDistributor.QueueName}"); - //} var updatedJobGroup = await groupService.Get() .Include(t => t.Jobs) @@ -415,8 +423,30 @@ namespace PARR.API.Controllers.V1 if (request.Schedule.Count() != orig.EsppSchValues.Count()) isScheduleChanged = true; - //if (request.IsAutoDistributionEnabled != orig.IsAutoDistributionEnabled) - // isScheduleChanged = true; + if (request.IsAutoDistributionEnabled != orig.IsAutoDistributionEnabled) + isScheduleChanged = true; + + if (request.DistributionConfig?.DistributionPeriodId != orig.DistributionConfig?.DistributionPeriodId) + isScheduleChanged = true; + + if (request.DistributionConfig?.IsExcludeWeekends != orig.DistributionConfig?.IsExcludeWeekends) + isScheduleChanged = true; + + if (request.DistributionConfig?.IsGroupingByWorkGroup != orig.DistributionConfig?.IsGroupingByWorkGroup) + isScheduleChanged = true; + + if (request.ScheduleExcludeTypeId != orig.ScheduleExcludeTypeId) + isScheduleChanged = true; + + if (request.ScheduleExcludeTypeCalendarId != orig.ScheduleExcludeTypeCalendarId) + isScheduleChanged = true; + + if (request.IsWorkGroupTimezone != orig.IsResponseAreaTimezone) + isScheduleChanged = true; + + if (request.UserTimeZoneOffsetMinutes != orig.UserTimeZoneOffsetMinutes) + isScheduleChanged = true; + request.Schedule.ForEach(requestSchedule => { diff --git a/PARR.API/Controllers/V1/JobGroupUpdateNextRunController.cs b/PARR.API/Controllers/V1/JobGroupUpdateNextRunController.cs new file mode 100644 index 00000000..588f004d --- /dev/null +++ b/PARR.API/Controllers/V1/JobGroupUpdateNextRunController.cs @@ -0,0 +1,70 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Controllers.V1.Base; +using PARR.API.Settings; +using PARR.BLL.Domain.Mq; +using PARR.BLL.Services.Interfaces; +using PARR.Common.Domain; +using PARR.Constants; +using PARR.DAL.Services.Interfaces.Job; +using Serilog.Core; + +namespace PARR.API.Controllers.V1 +{ + /// + /// Пересчитать все nextRun для JobGroup + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class JobGroupUpdateNextRunController : BaseApiController + { + private readonly IMqService mqService; + private readonly MqSettings mqSettings; + private readonly IJobGroupService jobGroupService; + + public JobGroupUpdateNextRunController( + IMqService mqService, + MqSettings mqSettings, + IJobGroupService jobGroupService + ) + { + this.mqService = mqService; + this.mqSettings = mqSettings; + this.jobGroupService = jobGroupService; + } + + + /// + /// Обновить nextRun для всех шаблонах в JobGroup + /// + /// + [HttpPost(ApiRoutes.JobGroupUpdateNextRun.UpdateNextRun)] + public async Task UpdateNextRun([FromRoute] Guid jobGroupId) + { + var jobGroup = await jobGroupService.Get().AnyAsync(t => t.Id == jobGroupId); + if (!jobGroup) + return BadRequest(new Response(null, false, new List { new ErrorModel { Message = "Не найдена группа работ с ИД" } })); + + var requestToMq = new NextRunUpdateMq + { + JobGroupId = jobGroupId, + Initiator = new HistoryInitiator + { + InitiatorComment = "Вручную отправлен запрос на обновление nextRun для группы работ", + InitiatorParrComponentId = ParrComponentsEnum.Api + } + }; + + var sendResult = await mqService.SendAsync(mqSettings.NextRun, new List { requestToMq }); + + if (sendResult.IsSuccess) + return Created("", new Response(null, true, new List(), "Отправлен запрос на расчет nextRun для группы работ.")); + else + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при отправке данных." } })); + + } + + } +} diff --git a/PARR.API/Settings/MqSettings.cs b/PARR.API/Settings/MqSettings.cs index 7d019ef8..c319aa22 100644 --- a/PARR.API/Settings/MqSettings.cs +++ b/PARR.API/Settings/MqSettings.cs @@ -10,6 +10,7 @@ namespace PARR.API.Settings public MqStatistics Statistics { get; set; } = new MqStatistics(); public MqTemplatesMatcher TemplatesMatcher { get; set; } = new MqTemplatesMatcher(); public MqTemplatesUpdater TemplatesUpdater { get; set; } = new MqTemplatesUpdater(); + public MqNextRun NextRun { get; set; } = new MqNextRun(); } public class MqGenerateTemplates : IMqSettings @@ -70,4 +71,13 @@ namespace PARR.API.Settings public string Password { get; set; } = string.Empty; public ushort? PrefetchCount { get; set; } = 0; } + + public class MqNextRun : IMqSettings + { + public string HostName { get; set; } = string.Empty; + public string QueueName { get; set; } = string.Empty; + public string User { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public ushort? PrefetchCount { get; set; } = 0; + } } diff --git a/PARR.API/appsettings.Development.json b/PARR.API/appsettings.Development.json index 0ae41385..7064c31d 100644 --- a/PARR.API/appsettings.Development.json +++ b/PARR.API/appsettings.Development.json @@ -45,6 +45,9 @@ "TemplatesUpdater": { "HostName": "10.99.253.216" }, + "NextRun": { + "HostName": "10.99.253.216" + }, "Statistics": { "StatMqAuth": { "HostName": "10.99.253.216" diff --git a/PARR.API/appsettings.json b/PARR.API/appsettings.json index c1568d59..d976bb4a 100644 --- a/PARR.API/appsettings.json +++ b/PARR.API/appsettings.json @@ -60,6 +60,12 @@ "User": "template_updater_writer", "Password": "sjdhgfkJHGIUFDi14asd^12" }, + "NextRun": { + "HostName": "parr-rabbitmq", + "QueueName": "parr-next-run-updater", + "User": "next_run_updater_writer", + "Password": "KJHGfdsjfhg$976412!kay" + }, "Statistics": { "StatMqAuth": { "HostName": "parr-rabbitmq", diff --git a/PARR.BLL/Domain/Mq/NextRunUpdateMq.cs b/PARR.BLL/Domain/Mq/NextRunUpdateMq.cs index c8fd050f..170f9819 100644 --- a/PARR.BLL/Domain/Mq/NextRunUpdateMq.cs +++ b/PARR.BLL/Domain/Mq/NextRunUpdateMq.cs @@ -1,4 +1,6 @@ -namespace PARR.BLL.Domain.Mq +using PARR.Common.Domain; + +namespace PARR.BLL.Domain.Mq { /// /// Запрос на обновление всех nextRun для JobGroup @@ -6,5 +8,7 @@ public class NextRunUpdateMq { public Guid JobGroupId { get; set; } + + public required HistoryInitiator Initiator { get; set; } } } diff --git a/PARR.NextRun/NextRunRabbitService.cs b/PARR.NextRun/NextRunRabbitService.cs index 2f3b6adf..6a465ee3 100644 --- a/PARR.NextRun/NextRunRabbitService.cs +++ b/PARR.NextRun/NextRunRabbitService.cs @@ -71,7 +71,7 @@ namespace PARR.NextRun return; } - await UpdateNextRunAsync(query.JobGroupId); + await UpdateNextRunAsync(query); } /// @@ -95,7 +95,7 @@ namespace PARR.NextRun /// /// /// - private async Task UpdateNextRunAsync(Guid jobGroupId) + private async Task UpdateNextRunAsync(NextRunUpdateMq queryMq) { using var scope = serviceProvider.CreateScope(); @@ -105,11 +105,11 @@ namespace PARR.NextRun // Берем шаблоны только в статусе Used var templates = await templateService.Get() .Where(t => - t.Job!.GroupId == jobGroupId + t.Job!.GroupId == queryMq.JobGroupId && t.StatusTypeId == TemplateStatusTypeEnum.Used ).ToListAsync(); - logger.LogInformation("Найдено шаблонов {count} шт. в статусе Used в группе работ {jobGroupId}", templates.Count, jobGroupId); + logger.LogInformation("Найдено шаблонов {count} шт. в статусе Used в группе работ {jobGroupId}", templates.Count, queryMq.JobGroupId); if (!templates.Any()) return; @@ -145,18 +145,18 @@ namespace PARR.NextRun if (updatedTemplates > 0) { - if (await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Запрос из очереди на перерасчет всех nextRun для jobGroupId", InitiatorParrComponentId = ParrComponentsEnum.NextRun })) + if (await templateService.CommitAsync(queryMq.Initiator)) { - logger.LogInformation("Успешно обновлены nextRun у {count} шаблонов, группа работ: {jobGroupId}", updatedTemplates, jobGroupId); + logger.LogInformation("Успешно обновлены nextRun у {count} шаблонов, группа работ: {jobGroupId}", updatedTemplates, queryMq.JobGroupId); } else { - logger.LogError("При сохранении nextRun для шаблонов {count} шт, произошла ошибка при сохранении в БД. JobGroupId: {jobGroupId}", updatedTemplates, jobGroupId); + logger.LogError("При сохранении nextRun для шаблонов {count} шт, произошла ошибка при сохранении в БД. JobGroupId: {jobGroupId}", updatedTemplates, queryMq.JobGroupId); } } else { - logger.LogInformation("Для группы работ {jobGroupId}, все nextRun актуальны. Нечего обновлять.", jobGroupId); + logger.LogInformation("Для группы работ {jobGroupId}, все nextRun актуальны. Нечего обновлять.", queryMq.JobGroupId); } } } diff --git a/PARR.NextRunWorker/RabbitWorker.cs b/PARR.NextRunWorker/RabbitWorker.cs index 3423eee3..4546f245 100644 --- a/PARR.NextRunWorker/RabbitWorker.cs +++ b/PARR.NextRunWorker/RabbitWorker.cs @@ -16,7 +16,7 @@ namespace PARR.NextRunWorker protected override async Task ExecuteAsync(CancellationToken stoppingToken) { logger.LogInformation("Запуск {workerName}", nameof(RabbitWorker)); - await nextRunRabbitService.StopAsync(); + await nextRunRabbitService.StartAsync(); } public override Task StopAsync(CancellationToken cancellationToken)