diff --git a/PARR.AIHITMainLoader/AihitMainLoader.cs b/PARR.AIHITMainLoader/AihitMainLoader.cs index 4d25c645..056ec037 100644 --- a/PARR.AIHITMainLoader/AihitMainLoader.cs +++ b/PARR.AIHITMainLoader/AihitMainLoader.cs @@ -3,8 +3,8 @@ using Microsoft.Extensions.Logging; using PARR.AIHITMainLoader.Models; using PARR.AIHITMainLoader.Services; using PARR.AIHITMainLoader.Settings; -using PARR.BLL.Domain.Mq; using PARR.BLL.Services.Interfaces; +using System.Text.Encodings.Web; using System.Text.Json; namespace PARR.AIHITMainLoader @@ -19,6 +19,11 @@ namespace PARR.AIHITMainLoader private readonly IMqService mqService; private readonly IServiceProvider serviceProvider; + private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + public AihitMainLoader( ILogger logger, IIntervalService intervalService, @@ -82,7 +87,7 @@ namespace PARR.AIHITMainLoader var mainData = item.ToMainData(); if (mainData == null) continue; - var json = JsonSerializer.Serialize(mainData); + var json = JsonSerializer.Serialize(mainData, jsonOptions); currentBatch.Add(json); // Отправка, если набрали полный пакет diff --git a/PARR.API/Contracts/V1/Requests/DistributeRequest.cs b/PARR.API/Contracts/V1/Requests/DistributeRequest.cs index 26b81422..1930a6b4 100644 --- a/PARR.API/Contracts/V1/Requests/DistributeRequest.cs +++ b/PARR.API/Contracts/V1/Requests/DistributeRequest.cs @@ -2,6 +2,6 @@ { public class DistributeRequest { - public Guid ApplicationInWorkId { get; set; } + public Guid JobGroupId { get; set; } } } diff --git a/PARR.API/Controllers/V1/AgentTaskController.cs b/PARR.API/Controllers/V1/AgentTaskController.cs index 1b555be5..6ce19693 100644 --- a/PARR.API/Controllers/V1/AgentTaskController.cs +++ b/PARR.API/Controllers/V1/AgentTaskController.cs @@ -24,21 +24,21 @@ namespace PARR.API.Controllers.V1 private readonly IClientService clientService; private readonly ITemplateService templateService; private readonly IUnitService unitService; - private readonly IEsppScheduleTransformService esppScheduleTransformService; + //private readonly IEsppScheduleTransformService esppScheduleTransformService; private readonly ILogger logger; public AgentTaskController( IClientService clientService, ITemplateService templateService, IUnitService unitService, - IEsppScheduleTransformService esppScheduleTransformService, + //IEsppScheduleTransformService esppScheduleTransformService, ILogger logger ) { this.clientService = clientService; this.templateService = templateService; this.unitService = unitService; - this.esppScheduleTransformService = esppScheduleTransformService; + //this.esppScheduleTransformService = esppScheduleTransformService; this.logger = logger; } @@ -51,82 +51,84 @@ namespace PARR.API.Controllers.V1 [HttpGet(ApiRoutes.AgentTask.GetByIp)] public async Task GetByClientIp([FromQuery] AgentTaskGetByIpQuery request) { - //ПАРР-ДВС-ПТК__ВРТ-DVGD-SDMI-WEB-01-ДВС__ПРОЧЕЕ(РАБОТЫ) - //10.99.253.65 - //2023-10-16 - var ip = request.Ip ?? clientService.GetClientIp()?.ToString(); + return Ok("Метод не реализован"); + ////ПАРР-ДВС-ПТК__ВРТ-DVGD-SDMI-WEB-01-ДВС__ПРОЧЕЕ(РАБОТЫ) + ////10.99.253.65 + ////2023-10-16 - if (string.IsNullOrEmpty(ip)) - return BadRequest(new Response(false, new List { new ErrorModel { Message = "Client IP address is null." } })); + //var ip = request.Ip ?? clientService.GetClientIp()?.ToString(); - //var date = request.Date ?? DateTimeOffset.UtcNow; - var date = DateTimeOffset.UtcNow; + //if (string.IsNullOrEmpty(ip)) + // return BadRequest(new Response(false, new List { new ErrorModel { Message = "Client IP address is null." } })); - //Агент получает задания, если `IsAgent = true`, шаблон и расписания активны, и статус синхронизации шаблона и расписания `= Ok`, и `NextRun = сегодня`, так же если у ApplicationInWork есть расписание. + ////var date = request.Date ?? DateTimeOffset.UtcNow; + //var date = DateTimeOffset.UtcNow; - // С одним IP может быть несколько информационных систем, так что может быть несколько хостов - var units = await unitService.GetWithIncludes().AsNoTracking().Where(t => t.UnitValues.Any(v => v.Field!.AihitName == "IP_АДРЕС" && v.Value!.Value == ip)).ToListAsync(); - var templates = await templateService.Get() - .Include(t => t.RobotConfigurations) - .Include(t => t.Job) - .ThenInclude(t=>t!.Group) - .ThenInclude(t => t!.EsppSchValues) - .Include(t => t.Unit) - .Where(t => units.Any(u=>u.Id == t.UnitId) - //&& t.ApplicationsInWork!.IsAgent == true//TODO Migration to job - && t.IsActiveTemplate == true - && t.IsActiveSchedule == true - //&& t.ApplicationsInWork!.NextRun.DateTime.Date == date.Date.Date - && t.NextRun.DateTime.Date == date.Date.Date - && t.RobotConfigurations.All(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok) - && t.Job!.Group!.EsppSchValues.Any()//.ApplicationsInWork.EsppSchValues.Any() - ).ToListAsync(); + ////Агент получает задания, если `IsAgent = true`, шаблон и расписания активны, и статус синхронизации шаблона и расписания `= Ok`, и `NextRun = сегодня`, так же если у ApplicationInWork есть расписание. - if (!templates.Any()) - return NoContent(); + //// С одним IP может быть несколько информационных систем, так что может быть несколько хостов + //var units = await unitService.GetWithIncludes().AsNoTracking().Where(t => t.UnitValues.Any(v => v.Field!.AihitName == "IP_АДРЕС" && v.Value!.Value == ip)).ToListAsync(); + //var templates = await templateService.Get() + // .Include(t => t.RobotConfigurations) + // .Include(t => t.Job) + // .ThenInclude(t=>t!.Group) + // .ThenInclude(t => t!.EsppSchValues) + // .Include(t => t.Unit) + // .Where(t => units.Any(u=>u.Id == t.UnitId) + // //&& t.ApplicationsInWork!.IsAgent == true//TODO Migration to job + // && t.IsActiveTemplate == true + // && t.IsActiveSchedule == true + // //&& t.ApplicationsInWork!.NextRun.DateTime.Date == date.Date.Date + // && t.NextRun.DateTime.Date == date.Date.Date + // && t.RobotConfigurations.All(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok) + // && t.Job!.Group!.EsppSchValues.Any()//.ApplicationsInWork.EsppSchValues.Any() + // ).ToListAsync(); - var response = new AgentTaskMinResponse - { - Scheduled = new List() - }; + //if (!templates.Any()) + // return NoContent(); - foreach (var template in templates) - { - //var templateSchedule = await esppScheduleTransformService.GetNextScheduleAsync(template.ApplicationInWorkId, template.ApplicationsInWork!.LastRun ?? template.ApplicationsInWork!.NextRun); - var templateSchedule = await esppScheduleTransformService.GetNextScheduleAsync(template.Job!.GroupId, template.NextRun); + //var response = new AgentTaskMinResponse + //{ + // Scheduled = new List() + //}; - if (!templateSchedule.Any()) - { - logger.LogWarning($"Запросили раписание для агента по NextRun и вернулся пустой список! Такого не должно быть! " + - $"JobGroupId: {template.Job.GroupId}, latRun: {template.LastRun}, NextRun: {template.NextRun}, ip: {ip}, date: {date}"); - continue; - } + //foreach (var template in templates) + //{ + // //var templateSchedule = await esppScheduleTransformService.GetNextScheduleAsync(template.ApplicationInWorkId, template.ApplicationsInWork!.LastRun ?? template.ApplicationsInWork!.NextRun); + // var templateSchedule = await esppScheduleTransformService.GetNextScheduleAsync(template.Job!.GroupId, template.NextRun); - if (string.IsNullOrEmpty(template.Job.Group!.AgentName) && string.IsNullOrEmpty(template.Job.Group!.AgentScript)) - { - logger.LogWarning($"Запросили задание для агента с пустыми значениями AgentName && AgentScript. Такого не должно быть! " + - $"JobGroupId: {template.Job.GroupId}, AgentName: {template.Job.Group.AgentName}, AgentScript: {template.Job.Group.AgentScript} , ip: {ip}, date: {date}"); - continue; - } + // if (!templateSchedule.Any()) + // { + // logger.LogWarning($"Запросили раписание для агента по NextRun и вернулся пустой список! Такого не должно быть! " + + // $"JobGroupId: {template.Job.GroupId}, latRun: {template.LastRun}, NextRun: {template.NextRun}, ip: {ip}, date: {date}"); + // continue; + // } - templateSchedule.ForEach(item => response.Scheduled.Add(new AgentTaskMinScheduleResponse - { - Name = template.Job.Group.AgentName ?? "", - Script = template.Job.Group.AgentScript ?? "", - StartAt = item, - TemplateId = template.Id - })); - } + // if (string.IsNullOrEmpty(template.Job.Group!.AgentName) && string.IsNullOrEmpty(template.Job.Group!.AgentScript)) + // { + // logger.LogWarning($"Запросили задание для агента с пустыми значениями AgentName && AgentScript. Такого не должно быть! " + + // $"JobGroupId: {template.Job.GroupId}, AgentName: {template.Job.Group.AgentName}, AgentScript: {template.Job.Group.AgentScript} , ip: {ip}, date: {date}"); + // continue; + // } - if (!response.Scheduled.Any()) - return NoContent(); + // templateSchedule.ForEach(item => response.Scheduled.Add(new AgentTaskMinScheduleResponse + // { + // Name = template.Job.Group.AgentName ?? "", + // Script = template.Job.Group.AgentScript ?? "", + // StartAt = item, + // TemplateId = template.Id + // })); + //} - response.Scheduled = response.Scheduled.OrderBy(t => t.StartAt).ToList(); + //if (!response.Scheduled.Any()) + // return NoContent(); - logger.LogInformation($"Агент с IP-адресом {ip} получил задания: [{string.Join(';', response.Scheduled.Select(s => $"StartAt:{s.StartAt}, Name:{s.Name}, TemplateId:{s.TemplateId}"))}]"); + //response.Scheduled = response.Scheduled.OrderBy(t => t.StartAt).ToList(); - return Ok(response); + //logger.LogInformation($"Агент с IP-адресом {ip} получил задания: [{string.Join(';', response.Scheduled.Select(s => $"StartAt:{s.StartAt}, Name:{s.Name}, TemplateId:{s.TemplateId}"))}]"); + + //return Ok(response); } } diff --git a/PARR.API/Controllers/V1/DistributorController.cs b/PARR.API/Controllers/V1/DistributorController.cs index f102f938..10dce4f5 100644 --- a/PARR.API/Controllers/V1/DistributorController.cs +++ b/PARR.API/Controllers/V1/DistributorController.cs @@ -5,10 +5,13 @@ using PARR.API.Contracts.V1; using PARR.API.Contracts.V1.Requests; using PARR.API.Contracts.V1.Responses.Base; using PARR.API.Controllers.V1.Base; +using PARR.API.Services.Interfaces; using PARR.API.Settings; using PARR.BLL.Domain.Mq; using PARR.BLL.Services.Interfaces; +using PARR.Common.Domain; using PARR.Constants; +using System.Text.Encodings.Web; using System.Text.Json; namespace PARR.API.Controllers.V1 @@ -22,21 +25,24 @@ namespace PARR.API.Controllers.V1 private readonly IMqService mqService; private readonly MqSettings mqSettings; private readonly IValidator validator; + private readonly IClientService clientService; public DistributorController( IMqService mqService, MqSettings mqSettings, - IValidator validator + IValidator validator, + IClientService clientService ) { this.mqService = mqService; this.mqSettings = mqSettings; this.validator = validator; + this.clientService = clientService; } /// - /// Перераспределить шаблоны для регламентной работы + /// Перераспределить шаблоны для группы работ /// /// [HttpPost(ApiRoutes.Distributor.Distribute)] @@ -48,17 +54,28 @@ namespace PARR.API.Controllers.V1 var requestToMq = new TemplateDistributorMq { - ApplicationInWorkId = request.ApplicationInWorkId + JobGroupId = request.JobGroupId, + Initiator = new HistoryInitiator + { + InitiatorComment = "Через API отправлен запрос на распределение шаблонов", + InitiatorIp = clientService.GetClientIp()?.ToString(), + InitiatorParrComponentId = ParrComponentsEnum.Api + } }; - var msg = JsonSerializer.Serialize(requestToMq); + //var jsonOptions = new JsonSerializerOptions + //{ + // Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + //}; + //var msg = JsonSerializer.Serialize(requestToMq, jsonOptions); - var sendResult = await mqService.SendAsync(mqSettings.TemplateDistributor, new[] { msg }); + //var sendResult = await mqService.SendAsync(mqSettings.TemplateDistributor, new[] { msg }); + var sendResult = await mqService.SendAsync(mqSettings.TemplateDistributor, new List { requestToMq }); if (sendResult.IsSuccess) return Created("", new Response(null, true, new List(), "Отправлен запрос на перераспределение регламентных работ.")); else - return BadRequest(new Response(false, new List { new ErrorModel { Message="Ошибка при отправке данных."} })); + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при отправке данных." } })); } } diff --git a/PARR.API/Controllers/V1/GeneratorTemplateController.cs b/PARR.API/Controllers/V1/GeneratorTemplateController.cs index 396ec4db..18ff6243 100644 --- a/PARR.API/Controllers/V1/GeneratorTemplateController.cs +++ b/PARR.API/Controllers/V1/GeneratorTemplateController.cs @@ -72,9 +72,10 @@ namespace PARR.API.Controllers.V1 HistoryInitiator = new HistoryInitiator { InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api } }; - var msg = JsonSerializer.Serialize(obj); + //var msg = JsonSerializer.Serialize(obj); - var _result = await mqService.SendAsync(mqSettings.GenerateTemplates, new[] { msg }); + //var _result = await mqService.SendAsync(mqSettings.GenerateTemplates, new[] { msg }); + var _result = await mqService.SendAsync(mqSettings.GenerateTemplates, new List { obj }); if (_result.IsSuccess == false) result = false; diff --git a/PARR.API/Controllers/V1/JobController.cs b/PARR.API/Controllers/V1/JobController.cs index e436baba..d99a286b 100644 --- a/PARR.API/Controllers/V1/JobController.cs +++ b/PARR.API/Controllers/V1/JobController.cs @@ -641,18 +641,20 @@ namespace PARR.API.Controllers.V1 } }; - var msg = JsonSerializer.Serialize(request); + //var msg = JsonSerializer.Serialize(request); + + //var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new[] { msg }); + var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new List { request }); - var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new[] { msg }); logger.LogDebug("Получен код отпрвки: {IsSuccess}", result.IsSuccess); if (!result.IsSuccess) { - logger.LogError($"Ошибка при отправке запроса в очередь на обновление связанных шаблонов, после обновления маски шаблона. {msg}"); + logger.LogError($"Ошибка при отправке запроса в очередь на обновление связанных шаблонов, после обновления маски шаблона. {request.ToJson()}"); return false; } - logger.LogInformation($"После изменения маски шаблона в jobId: {jobId}, отправлен запрос в очередь на переименование связанных шаблонов: {msg}"); + logger.LogInformation($"После изменения маски шаблона в jobId: {jobId}, отправлен запрос в очередь на переименование связанных шаблонов: {request.ToJson()}"); return true; } diff --git a/PARR.API/Controllers/V1/RobotTaskController.cs b/PARR.API/Controllers/V1/RobotTaskController.cs index 7a7e3d09..a601af7d 100644 --- a/PARR.API/Controllers/V1/RobotTaskController.cs +++ b/PARR.API/Controllers/V1/RobotTaskController.cs @@ -14,6 +14,7 @@ using PARR.DAL.Contracts; using PARR.DAL.DomainServices.Shortcodes; using PARR.DAL.DomainServices.Shortcodes.Models; using PARR.DAL.Models; +using PARR.DAL.NextRunServices; using PARR.DAL.Services.Interfaces; using PARR.DAL.TransformServices; @@ -25,31 +26,34 @@ namespace PARR.API.Controllers.V1 private readonly IMapper mapper; private readonly SettingsFromDb settingsFromDb; private readonly IRobotConfigurationService robotConfigurationService; - private readonly IEsppScheduleTransformService esppScheduleTransformService; + //private readonly IEsppScheduleTransformService esppScheduleTransformService; private readonly ILogger logger; private readonly IClientService clientService; private readonly IRobotHistoryService robotHistoryService; private readonly IShortcodesService shortcodesService; + private readonly INextRunService nextRunService; public RobotTaskController( IMapper mapper, SettingsFromDb settingsFromDb, IRobotConfigurationService robotConfigurationService, - IEsppScheduleTransformService esppScheduleTransformService, + //IEsppScheduleTransformService esppScheduleTransformService, ILogger logger, IClientService clientService, IRobotHistoryService robotHistoryService, - IShortcodesService shortcodesService + IShortcodesService shortcodesService, + INextRunService nextRunService ) { this.mapper = mapper; this.settingsFromDb = settingsFromDb; this.robotConfigurationService = robotConfigurationService; - this.esppScheduleTransformService = esppScheduleTransformService; + //this.esppScheduleTransformService = esppScheduleTransformService; this.logger = logger; this.clientService = clientService; this.robotHistoryService = robotHistoryService; this.shortcodesService = shortcodesService; + this.nextRunService = nextRunService; } @@ -306,7 +310,8 @@ namespace PARR.API.Controllers.V1 //пока у нас выключено автораспределение, считает по refDate //TODO: когда заработает автораспределение, будем думать!!!!! - var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate); + //var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate); + var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false); if (nextRun != template.NextRun) { diff --git a/PARR.API/Controllers/V1/SyncTaskController.cs b/PARR.API/Controllers/V1/SyncTaskController.cs index 30ad6f34..ec7767ef 100644 --- a/PARR.API/Controllers/V1/SyncTaskController.cs +++ b/PARR.API/Controllers/V1/SyncTaskController.cs @@ -73,10 +73,11 @@ namespace PARR.API.Controllers.V1 } }; - var msg = JsonSerializer.Serialize(matchTemplateTask); - logger.LogDebug("Подготовлено сообщение: {Message}", new[] { msg }); + //var msg = JsonSerializer.Serialize(matchTemplateTask); + //logger.LogDebug("Подготовлено сообщение: {Message}", new[] { msg }); - var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new[] { msg }); + //var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new[] { msg }); + var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new List { matchTemplateTask }); logger.LogDebug("Получен код отпрвки: {IsSuccess}", result.IsSuccess); if (!result.IsSuccess) diff --git a/PARR.API/Controllers/V1/TemplateActivatorController.cs b/PARR.API/Controllers/V1/TemplateActivatorController.cs index 24a2af7c..e006910b 100644 --- a/PARR.API/Controllers/V1/TemplateActivatorController.cs +++ b/PARR.API/Controllers/V1/TemplateActivatorController.cs @@ -67,9 +67,10 @@ namespace PARR.API.Controllers.V1 HistoryInitiator = new HistoryInitiator { InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api } }; - var msg = JsonSerializer.Serialize(mqRequest); + //var msg = JsonSerializer.Serialize(mqRequest); - var sendResult = await mqService.SendAsync(mqSettings.TemplateActivator, new[] { msg }); + //var sendResult = await mqService.SendAsync(mqSettings.TemplateActivator, new[] { msg }); + var sendResult = await mqService.SendAsync(mqSettings.TemplateActivator, new List { mqRequest }); if (!sendResult.IsSuccess) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при отправке данных." } })); diff --git a/PARR.API/Controllers/V1/TestController.cs b/PARR.API/Controllers/V1/TestController.cs index 0d93d817..75770c1a 100644 --- a/PARR.API/Controllers/V1/TestController.cs +++ b/PARR.API/Controllers/V1/TestController.cs @@ -25,7 +25,7 @@ namespace PARR.API.Controllers.V1 public class TestController : BaseApiController { private readonly IClientService clientService; - private readonly IEsppScheduleTransformService esppScheduleTransformService; + //private readonly IEsppScheduleTransformService esppScheduleTransformService; private readonly IRedisCacheService redisCacheService; private readonly IWeekendDayService weekendDayService; private readonly IUnitService unitService; @@ -37,7 +37,7 @@ namespace PARR.API.Controllers.V1 public TestController( IClientService clientService, - IEsppScheduleTransformService esppScheduleTransformService, + //IEsppScheduleTransformService esppScheduleTransformService, IRedisCacheService redisCacheService, IWeekendDayService weekendDayService, IUnitService unitService, @@ -49,7 +49,7 @@ namespace PARR.API.Controllers.V1 ) { this.clientService = clientService; - this.esppScheduleTransformService = esppScheduleTransformService; + //this.esppScheduleTransformService = esppScheduleTransformService; this.redisCacheService = redisCacheService; this.weekendDayService = weekendDayService; this.unitService = unitService; @@ -76,32 +76,32 @@ namespace PARR.API.Controllers.V1 } - /// - /// Получить следующую дату запуска - /// - /// - /// - /// - [HttpGet(ApiRoutes.Test.GetNextScheduleDate)] - public async Task GetNextScheduleDate([FromRoute] Guid applicationInWorkId, [FromRoute] DateTimeOffset lastRunDate) - { - var result = await esppScheduleTransformService.GetNextDateAsync(applicationInWorkId, lastRunDate); - return Ok(result); - } + ///// + ///// Получить следующую дату запуска + ///// + ///// + ///// + ///// + //[HttpGet(ApiRoutes.Test.GetNextScheduleDate)] + //public async Task GetNextScheduleDate([FromRoute] Guid applicationInWorkId, [FromRoute] DateTimeOffset lastRunDate) + //{ + // var result = await esppScheduleTransformService.GetNextDateAsync(applicationInWorkId, lastRunDate); + // return Ok(result); + //} - /// - /// Получить следующее расписание - /// - /// - /// - /// - [HttpGet(ApiRoutes.Test.GetNextSchedule)] - public async Task GetNextSchedule([FromRoute] Guid applicationInWorkId, [FromRoute] DateTimeOffset lastRunDate) - { - var result = await esppScheduleTransformService.GetNextScheduleAsync(applicationInWorkId, lastRunDate); - return Ok(result); - } + ///// + ///// Получить следующее расписание + ///// + ///// + ///// + ///// + //[HttpGet(ApiRoutes.Test.GetNextSchedule)] + //public async Task GetNextSchedule([FromRoute] Guid applicationInWorkId, [FromRoute] DateTimeOffset lastRunDate) + //{ + // var result = await esppScheduleTransformService.GetNextScheduleAsync(applicationInWorkId, lastRunDate); + // return Ok(result); + //} /// diff --git a/PARR.API/Validators/DistributeRequestValidator.cs b/PARR.API/Validators/DistributeRequestValidator.cs index 2f051a46..f7826eae 100644 --- a/PARR.API/Validators/DistributeRequestValidator.cs +++ b/PARR.API/Validators/DistributeRequestValidator.cs @@ -1,24 +1,27 @@ using FluentValidation; +using Microsoft.EntityFrameworkCore; using PARR.API.Contracts.V1.Requests; -using PARR.DAL.Services.Interfaces; +using PARR.DAL.Services.Interfaces.Job; namespace PARR.API.Validators { public class DistributeRequestValidator : AbstractValidator { - private readonly IApplicationsInWorkService applicationsInWorkService; - - public DistributeRequestValidator(IApplicationsInWorkService applicationsInWorkService) + public DistributeRequestValidator(IJobGroupService jobGroupService) { - this.applicationsInWorkService = applicationsInWorkService; - - - RuleFor(t => t.ApplicationInWorkId).NotEmpty().MustAsync(async (entity, value, c) => + RuleFor(t => t.JobGroupId).NotEmpty().MustAsync(async (entity, value, c) => { - var appInWork = await applicationsInWorkService.GetAsync(value); - - return appInWork != null; + return await jobGroupService.Get().FirstOrDefaultAsync(t => t.Id == value) != null; }).WithMessage("Недопустимое значение"); + + RuleFor(t => t.JobGroupId).NotEmpty().MustAsync(async (entity, value, c) => + { + var jobGroup = await jobGroupService.Get() + .Include(t => t.DistributionConfig) + .FirstOrDefaultAsync(t => t.Id == value); + + return jobGroup != null && jobGroup.IsAutoDistributionEnabled && jobGroup.DistributionConfig != null; + }).WithMessage("Отсутствуют настройки автораспределения"); } } } diff --git a/PARR.BLL/Domain/Mq/TemplateDistributorMq.cs b/PARR.BLL/Domain/Mq/TemplateDistributorMq.cs index 38bcfd5e..63b88e5f 100644 --- a/PARR.BLL/Domain/Mq/TemplateDistributorMq.cs +++ b/PARR.BLL/Domain/Mq/TemplateDistributorMq.cs @@ -1,10 +1,14 @@ -namespace PARR.BLL.Domain.Mq +using PARR.Common.Domain; + +namespace PARR.BLL.Domain.Mq { /// - /// Модель в MQ, обновления расписаний шаблонов связанных с РР (для TemplateDistributor) + /// Модель в MQ, распределить шаблоны для JobGroupId (для TemplateDistributor) /// public class TemplateDistributorMq { - public Guid ApplicationInWorkId { get; set; } + public Guid JobGroupId { get; set; } + + public required HistoryInitiator Initiator { get; set; } } } diff --git a/PARR.BLL/Services/Implementations/MqServiceV2.cs b/PARR.BLL/Services/Implementations/MqServiceV2.cs index 11282afd..c56cd347 100644 --- a/PARR.BLL/Services/Implementations/MqServiceV2.cs +++ b/PARR.BLL/Services/Implementations/MqServiceV2.cs @@ -5,6 +5,8 @@ using PARR.BLL.Services.Interfaces; using RabbitMQ.Client; using RabbitMQ.Client.Events; using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; namespace PARR.BLL.Services.Implementations { @@ -17,6 +19,11 @@ namespace PARR.BLL.Services.Implementations // реализация для RabbitMQ.Client 7.1.2 + private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + public MqServiceV2(ILogger logger) { this.logger = logger; @@ -108,6 +115,12 @@ namespace PARR.BLL.Services.Implementations } } + public async Task SendAsync(IMqSettings mqSettings, List msgObjectList) + { + var msgStringList = msgObjectList.Select(t => JsonSerializer.Serialize(t, jsonOptions)).ToArray(); + + return await SendAsync(mqSettings, msgStringList); + } public async Task SendAsync(IMqSettings mqSettings, string[] msgList) { @@ -136,7 +149,8 @@ namespace PARR.BLL.Services.Implementations props.DeliveryMode = DeliveryModes.Persistent; //время жизни, мс //props.Expiration = "60000"; - props.ContentType = "text/plain";//"application/json"; + //props.ContentType = "text/plain";//"application/json"; + props.ContentType = "text/plain; charset=utf-8";//"application/json"; channel.BasicReturnAsync += async (sender, ea) => { diff --git a/PARR.BLL/Services/Interfaces/IMqService.cs b/PARR.BLL/Services/Interfaces/IMqService.cs index 52344182..65af0579 100644 --- a/PARR.BLL/Services/Interfaces/IMqService.cs +++ b/PARR.BLL/Services/Interfaces/IMqService.cs @@ -8,6 +8,22 @@ namespace PARR.BLL.Services.Interfaces public interface IMqService : IAsyncDisposable // IDisposable { Task InitConsumerAsync(IMqSettings mqSettings, MqMessageHandlerDelegate messageHandler); + + /// + /// Отправить сообщение в очередь используя список строк + /// !!! Избавиться от этого метода, вместо него использовать со списком объектов !!! + /// + /// + /// + /// Task SendAsync(IMqSettings mqSettings, string[] msgList); + + /// + /// Отправить сообщение в очередь используя список объектов + /// + /// + /// + /// + Task SendAsync(IMqSettings mqSettings, List msgObjectList); } } diff --git a/PARR.DAL/NextRunServices/INextRunService.cs b/PARR.DAL/NextRunServices/INextRunService.cs index 3800f9f9..a130620e 100644 --- a/PARR.DAL/NextRunServices/INextRunService.cs +++ b/PARR.DAL/NextRunServices/INextRunService.cs @@ -1,4 +1,6 @@ -namespace PARR.DAL.NextRunServices +using PARR.DAL.NextRunServices.Models; + +namespace PARR.DAL.NextRunServices { public interface INextRunService { @@ -7,24 +9,32 @@ /// /// /// - Task> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId); + Task?> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId); + + + ///// + ///// Получить NextRun по jobGroupId с расписанием ЕСПП + ///// + ///// + ///// + //Task GetNextRunForJobGroupWithEsppSchedulleAsync(Guid jobGroupId); /// - /// Получить NextRun по jobGroupId с расписанием ЕСПП + /// Получить nextRun для создаваемого шаблона, которого еще нет в БД /// /// /// - Task GetNextRunForJobGroupWithEsppSchedulleAsync(Guid jobGroupId); + Task GetNextRunForNewTemplateAsync(Guid jobGroupId); /// - /// Получить NextRun по id шаблона + /// Получить NextRun по id существующего шаблона /// /// - /// Новый шаблон или шаблон переведенный из unused + /// Шаблон переведенный из unused /// - Task GetNextRunForTemplate(Guid templateId, bool isNew); + Task GetNextRunForTemplateAsync(Guid templateId, bool isNew); } } diff --git a/PARR.DAL/NextRunServices/Models/TemplateWithWorkGroupDto.cs b/PARR.DAL/NextRunServices/Models/TemplateWithWorkGroupDto.cs new file mode 100644 index 00000000..cdae20a5 --- /dev/null +++ b/PARR.DAL/NextRunServices/Models/TemplateWithWorkGroupDto.cs @@ -0,0 +1,5 @@ +namespace PARR.DAL.NextRunServices.Models +{ + internal record TemplateWithWorkGroupDto(Guid Id, DateTimeOffset? NextRun, string WorkGroup); + +} diff --git a/PARR.DAL/NextRunServices/NextRunService.cs b/PARR.DAL/NextRunServices/NextRunService.cs index ff5348b7..ba484c4e 100644 --- a/PARR.DAL/NextRunServices/NextRunService.cs +++ b/PARR.DAL/NextRunServices/NextRunService.cs @@ -1,6 +1,10 @@ - -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using PARR.Constants; +using PARR.DAL.DomainServices.Shortcodes; +using PARR.DAL.Models; +using PARR.DAL.Models.Job; +using PARR.DAL.NextRunServices.Models; using PARR.DAL.NextRunServices.Subservices; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; @@ -15,13 +19,15 @@ namespace PARR.DAL.NextRunServices private readonly IJobGroupService jobGroupService; private readonly IEsppScheduleTransformService esppScheduleTransformService; private readonly ITemplateDistributor templateDistributor; + private readonly IShortcodesService shortcodesService; public NextRunService( ILogger logger, ITemplateService templateService, IJobGroupService jobGroupService, IEsppScheduleTransformService esppScheduleTransformService, - ITemplateDistributor templateDistributor + ITemplateDistributor templateDistributor, + IShortcodesService shortcodesService ) { this.logger = logger; @@ -29,20 +35,121 @@ namespace PARR.DAL.NextRunServices this.jobGroupService = jobGroupService; this.esppScheduleTransformService = esppScheduleTransformService; this.templateDistributor = templateDistributor; + this.shortcodesService = shortcodesService; } - public async Task> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId) + public async Task?> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId) { - //TODO: - throw new NotImplementedException(); - //var ditributedTemplateList = await templateDistributor.DistributeTemplatesAsync(); + logger.LogInformation("Начинаю распределять шаблоны для группы работ {gobGroupId}", jobGroupId); + + var jobGroup = await jobGroupService.Get() + .Include(t => t.DistributionConfig) + .ThenInclude(t => t.DistributionPeriod) + .AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == jobGroupId); + + if (jobGroup == null) + { + logger.LogError("Не найдена группа работа с id: {id}", jobGroupId); + return null; + } + + if (!jobGroup.IsAutoDistributionEnabled || jobGroup.DistributionConfig == null) + { + logger.LogError("Группа работ id: {id} не подходит для автораспределения, у нее или отсутствуют настройки или не включено автораспределение. IsAutoDistributionEnabled: {IsAutoDistributionEnabled}. Есть конфиг: {DistributionConfig}", jobGroupId, jobGroup.IsAutoDistributionEnabled, jobGroup.DistributionConfig != null); + return null; + } + + logger.LogInformation("Параметры распределения. groupId: {groupId}, name: {groupName}, referenceDate: {referenceDate}, " + + "distributionPeriodName: {distributionPeriodName}, distributionPeriodDuration: {distributionPeriodDuration}, " + + "distributionPeriodType: {distributionPeriodType}, IsExcludeWeekends: {IsExcludeWeekends}, IsGroupingByWorkGroup: {IsGroupingByWorkGroup}", + jobGroupId, jobGroup.GroupName, jobGroup.ReferenceDate, jobGroup.DistributionConfig.DistributionPeriod.Name, jobGroup.DistributionConfig.DistributionPeriod.Duration, jobGroup.DistributionConfig.DistributionPeriod.Type, + jobGroup.DistributionConfig.IsExcludeWeekends, jobGroup.DistributionConfig.IsGroupingByWorkGroup + ); + + var duration = GetDurationDays(jobGroup.DistributionConfig); + var dateStart = GetDateStart(jobGroup.ReferenceDate); + + var allTemplates = await templateService.Get() + .Include(t => t.Job) + .Where(t => t.Job!.GroupId == jobGroupId) + .AsNoTracking() + .ToListAsync(); + if (!allTemplates.Any()) + { + logger.LogInformation("В группе c ИД {jobGroupId} отсутствуют шаблоны", jobGroupId); + return null; + } + + logger.LogDebug("Всего шаблонов для распределения: {count} шт.", allTemplates.Count); + + var result = new List(); + + if (jobGroup.DistributionConfig.IsGroupingByWorkGroup) + { + // Нужно группировать по РГ + + // список шаблонов с полученной из шорткода РГ + var templatesWithWorkGroup = new List(); + foreach (var template in allTemplates) + { + var workGroupName = await shortcodesService.ApplyShortcodesAsync(template.Job!.WorkGroupMask, template); + templatesWithWorkGroup.Add(new TemplateWithWorkGroupDto(template.Id, template.NextRun, workGroupName)); + } + + var grouping = templatesWithWorkGroup.GroupBy(t => t.WorkGroup); + + //распределяем + foreach (var workGroupTemplates in grouping) + { + logger.LogInformation("Начинаю распределять шаблоны для рабочей группы: {workGroup}. Всего шаблонов: {countTemplates} шт.", workGroupTemplates.Key, workGroupTemplates.Count()); + var templatesForDistribute = workGroupTemplates.Select(t => new TemplateNextRunDto(t.Id, t.NextRun)).ToList(); + var distributedResult = await templateDistributor.DistributeTemplatesAsync(dateStart, duration, jobGroup.ReferenceDate, templatesForDistribute, jobGroup.DistributionConfig.IsExcludeWeekends); + + result.AddRange(distributedResult); + } + } + else + { + // Не нужна группировка по РГ + + // сразу распределяем все шаблоны + var templatesForDistribute = allTemplates.Select(t => new TemplateNextRunDto(t.Id, t.NextRun)).ToList(); + + result = await templateDistributor.DistributeTemplatesAsync(dateStart, duration, jobGroup.ReferenceDate, templatesForDistribute, jobGroup.DistributionConfig.IsExcludeWeekends); + } + + logger.LogInformation("Завершено распределение шаблонов для группы {jobGroupId}. Всего распределено шаблонов: {count} шт.", jobGroupId, result.Count); + + return result; } - public async Task GetNextRunForJobGroupWithEsppSchedulleAsync(Guid jobGroupId) + //public async Task GetNextRunForJobGroupWithEsppSchedulleAsync(Guid jobGroupId) + //{ + // var jobGroup = await jobGroupService.Get().AsNoTracking().FirstOrDefaultAsync(t => t.Id == jobGroupId); + + // if (jobGroup == null) + // { + // logger.LogError("Не найдена группа работ с Id: {jobGroupId}.", jobGroupId); + // throw new ArgumentNullException(nameof(jobGroupId), $"Не найдена группа работ с Id: {jobGroupId}"); + // } + + // // Берем из обычного расписания ЕСПП + // return await esppScheduleTransformService.GetNextDateAsync(jobGroupId, jobGroup.ReferenceDate); + //} + + + public async Task GetNextRunForNewTemplateAsync(Guid jobGroupId) { - var jobGroup = await jobGroupService.Get().AsNoTracking().FirstOrDefaultAsync(t => t.Id == jobGroupId); + // определяю это автораспределение или нет, вызываю соответствующий рассчет + + var jobGroup = await jobGroupService.Get() + .Include(t => t.DistributionConfig) + .ThenInclude(t => t.DistributionPeriod) + .AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == jobGroupId); if (jobGroup == null) { @@ -50,36 +157,152 @@ namespace PARR.DAL.NextRunServices throw new ArgumentNullException(nameof(jobGroupId), $"Не найдена группа работ с Id: {jobGroupId}"); } - // Берем из обычного расписания ЕСПП - return await esppScheduleTransformService.GetNextDateAsync(jobGroupId, jobGroup.ReferenceDate); + if (jobGroup.IsAutoDistributionEnabled) + { + // тут автораспределение + + if (jobGroup.DistributionConfig == null) + { + logger.LogError("Для группы работ {jobGroupId}, указано автораспределение, но отсутствует конфиг в таблице {GroupDistributionConfigs}", jobGroupId, nameof(JobGroupDistributionConfig)); + throw new ArgumentNullException(nameof(JobGroupDistributionConfig), $"Для jobGroupId: {jobGroupId} отсутствует конфигурация автораспределения в таблице {nameof(JobGroupDistributionConfig)}"); + } + + #region Вынести в одтельный метод, почти все повторяется + var dateStart = GetDateStart(jobGroup.ReferenceDate); + var duration = GetDurationDays(jobGroup.DistributionConfig); + + var result = await templateDistributor.GetValidNextRunForTemplateAsync(dateStart, + duration, + jobGroup.ReferenceDate, + new TemplateNextRunDto(Guid.Empty, null), + //TODO: тут пока не получаем список шаблонов, но позже, когда будем строить каждый раз план, нужно будет сюда передавать список связанных шаблонов + new List(), + jobGroup.DistributionConfig.IsExcludeWeekends, + isNew: true + ); + + #endregion + logger.LogDebug("Получил nextRun {nextRun} по jobGroupId {jobGroupId} для нового шаблона, тип расписания: автораспределение", result.NextRun, jobGroupId); + + return result.NextRun; + } + else + { + // тут расписание ЕСПП + var nextRun = await esppScheduleTransformService.GetNextDateAsync(jobGroup.Id, jobGroup.ReferenceDate); + logger.LogDebug("Получил nextRun {nextRun} по jobGroupId {jobGroupId}, тип расписания ЕСПП", nextRun, jobGroupId); + + return nextRun; + } } - public async Task GetNextRunForTemplate(Guid templateId, bool isNew) + public async Task GetNextRunForTemplateAsync(Guid templateId, bool isNew) { var template = await templateService.Get() - .Include(t => t.Job).ThenInclude(t => t.Group) + .Include(t => t.Job) + .ThenInclude(t => t.Group).ThenInclude(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod) .AsNoTracking() .FirstOrDefaultAsync(t => t.Id == templateId); if (template == null) { - logger.LogError("Не найдена шаблон с Id: {templateId}.", templateId); - throw new ArgumentNullException(nameof(templateId), $"Не найдена шаблон с Id: {templateId}"); + logger.LogError("Не найден шаблон с Id: {templateId}.", templateId); + throw new ArgumentNullException(nameof(templateId), $"Не найден шаблон с Id: {templateId}"); } if (template.Job!.Group!.IsAutoDistributionEnabled == true) { // включено автораспределение - //TODO: !!!!!!!!!!!!!!!! добавить метод рассчета с учетом распределения - throw new NotImplementedException(); - //return await templateDistributor.GetValidNextRunForTemplateAsync(); + if (template.Job!.Group.DistributionConfig == null) + { + logger.LogError("Для шаблона {templateId}, jobGroupId {jobGroupId}, указано автораспределение, но отсутствует конфиг в таблице {GroupDistributionConfigs}", template.Id, template.Job.GroupId, nameof(JobGroupDistributionConfig)); + throw new ArgumentNullException(nameof(JobGroupDistributionConfig), $"Для jobGroupId: {template.Job.GroupId} отсутствует конфигурация автораспределения в таблице {nameof(JobGroupDistributionConfig)}"); + } + + #region Вынести в одтельный метод, почти все повторяется + var dateStart = GetDateStart(template.Job!.Group.ReferenceDate); + var duration = GetDurationDays(template.Job!.Group.DistributionConfig); + + var result = await templateDistributor.GetValidNextRunForTemplateAsync(dateStart, + duration, + template.Job.Group.ReferenceDate, + new TemplateNextRunDto(template.Id, template.NextRun), + //TODO: тут пока не получаем список шаблонов, но позже, когда будем строить каждый раз план, нужно будет сюда передавать список связанных шаблонов + new List(), + template.Job.Group.DistributionConfig.IsExcludeWeekends, + isNew + ); + #endregion + + logger.LogDebug("Получил nextRun {nextRun} по templateId {templateId}, isNew: {isNew}, тип расписания: автораспределение", result.NextRun, templateId, isNew); + + return result.NextRun; + } else { // считаем как ЕСПП - return await esppScheduleTransformService.GetNextDateAsync(template.Job.Group.Id, template.Job.Group.ReferenceDate); + var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job.Group.Id, template.Job.Group.ReferenceDate); + logger.LogDebug("Получил nextRun {nextRun} по templateId {templateId}, isNew: {isNew}, тип расписания: ЕСПП", nextRun, templateId, isNew); + + return nextRun; } } + + + + + + /// + /// Получить продолжительность в днях + /// + /// + /// + private int GetDurationDays(JobGroupDistributionConfig config) + { + var period = config.DistributionPeriod; + var periodType = period!.Type; + int.TryParse(period.Duration, out var duration); + + var periodDays = duration; + + if (periodType == DistributionPeriodTypeEnum.Day.ToString()) + periodDays = duration; + + + if (periodType == DistributionPeriodTypeEnum.Month.ToString()) + // в месяце 30 дней, duration*30 + periodDays = duration * 30; + + + if (periodType == DistributionPeriodTypeEnum.Year.ToString()) + // в году 365 дней, duration*365 + periodDays = duration * 365; + + + logger.LogDebug("Период распределения: {name}, duration: {duration}, type: {type}. Итого в днях: {days}", period.Name, period.Duration, period.Type, periodDays); + + if (periodDays == 0) + logger.LogWarning("Период распределения 0 дней. Неверный конфиг распределения в таблице {table}. {name}, duration: {duration}, type: {type}", nameof(DistributionPeriod), period.Name, period.Duration, period.Type); + + return periodDays; + } + + + /// + /// Получить дату начала распределения + /// + /// + /// + private DateOnly GetDateStart(DateTimeOffset referenceDate) + { + var today = DateTime.UtcNow; + + if (today < referenceDate) + return DateOnly.FromDateTime(referenceDate.Date); + else + return DateOnly.FromDateTime(today.Date); + } } } diff --git a/PARR.DAL/TransformServices/EsppScheduleTransformService.cs b/PARR.DAL/TransformServices/EsppScheduleTransformService.cs index bdca7091..57c0ffe3 100644 --- a/PARR.DAL/TransformServices/EsppScheduleTransformService.cs +++ b/PARR.DAL/TransformServices/EsppScheduleTransformService.cs @@ -68,7 +68,7 @@ namespace PARR.DAL.TransformServices return GetNextDate(esppSchedule, referenceDate); } - public DateTimeOffset GetNextDate(EsppScheduleDto esppSchedule, DateTimeOffset referenceDate) + private DateTimeOffset GetNextDate(EsppScheduleDto esppSchedule, DateTimeOffset referenceDate) { var nextRun = referenceDate; @@ -111,62 +111,62 @@ namespace PARR.DAL.TransformServices } - private List GetNextSchedule(EsppScheduleDto esppSchedule, DateTimeOffset referenceDate) - { - // расписание на оставшееся на сегодня время. его так мало... - referenceDate = referenceDate.UtcDateTime; - var schedules = new List(); - var curTime = referenceDate; + //private List GetNextSchedule(EsppScheduleDto esppSchedule, DateTimeOffset referenceDate) + //{ + // // расписание на оставшееся на сегодня время. его так мало... + // referenceDate = referenceDate.UtcDateTime; + // var schedules = new List(); + // var curTime = referenceDate; - //Если ещё не произошло то добавляем расписание, возможно это новое AiW и он ещё ниразу не запускался. - //lastRun это будущее - if (referenceDate >= DateTimeOffset.UtcNow && referenceDate <= DateTimeOffset.UtcNow.EndOfDay()) - schedules.Add(referenceDate); + // //Если ещё не произошло то добавляем расписание, возможно это новое AiW и он ещё ниразу не запускался. + // //lastRun это будущее + // if (referenceDate >= DateTimeOffset.UtcNow && referenceDate <= DateTimeOffset.UtcNow.EndOfDay()) + // schedules.Add(referenceDate); - while (curTime < DateTimeOffset.UtcNow.EndOfDay()) - { - switch (esppSchedule.TypeSchedule.Id) - { - case (int)EsppSchTypeScheduleEnum.Regularly: - curTime = GetNextDateRegularly(esppSchedule.Values, curTime); - break; - case (int)EsppSchTypeScheduleEnum.Weekly: - curTime = GetNextDateWeekly(esppSchedule.Values, curTime); - break; - case (int)EsppSchTypeScheduleEnum.Monthly: - curTime = GetNextDateMonthly(esppSchedule.Values, curTime); - break; - case (int)EsppSchTypeScheduleEnum.Monthly2: - curTime = GetNextDateMonthly2(esppSchedule.Values, curTime); - break; - case (int)EsppSchTypeScheduleEnum.Annually: - curTime = GetNextDateAnnually(esppSchedule.Values, curTime); - break; - case (int)EsppSchTypeScheduleEnum.Annually2: - curTime = GetNextDateAnnually2(esppSchedule.Values, curTime); - break; - } + // while (curTime < DateTimeOffset.UtcNow.EndOfDay()) + // { + // switch (esppSchedule.TypeSchedule.Id) + // { + // case (int)EsppSchTypeScheduleEnum.Regularly: + // curTime = GetNextDateRegularly(esppSchedule.Values, curTime); + // break; + // case (int)EsppSchTypeScheduleEnum.Weekly: + // curTime = GetNextDateWeekly(esppSchedule.Values, curTime); + // break; + // case (int)EsppSchTypeScheduleEnum.Monthly: + // curTime = GetNextDateMonthly(esppSchedule.Values, curTime); + // break; + // case (int)EsppSchTypeScheduleEnum.Monthly2: + // curTime = GetNextDateMonthly2(esppSchedule.Values, curTime); + // break; + // case (int)EsppSchTypeScheduleEnum.Annually: + // curTime = GetNextDateAnnually(esppSchedule.Values, curTime); + // break; + // case (int)EsppSchTypeScheduleEnum.Annually2: + // curTime = GetNextDateAnnually2(esppSchedule.Values, curTime); + // break; + // } - schedules.Add(curTime); - } - schedules.RemoveAll(s => s > DateTimeOffset.UtcNow.EndOfDay()); + // schedules.Add(curTime); + // } + // schedules.RemoveAll(s => s > DateTimeOffset.UtcNow.EndOfDay()); - return schedules.OrderBy(t => t).ToList(); - } + // return schedules.OrderBy(t => t).ToList(); + //} - public async Task> GetNextScheduleAsync(Guid jobGroupId, DateTimeOffset referenceDate) - { - //TODO: тут не проверен переход через выходные дни!!! Переход не используется, так как тут не рассчитываем NextRun. - //В общем проверить, когда будем тестировать агента, что с датами все ок - var esppSchedule = await GetEsppScheduleAsync(jobGroupId); - var nextSchedule = GetNextSchedule(esppSchedule, referenceDate); + //public async Task> GetNextScheduleAsync(Guid jobGroupId, DateTimeOffset referenceDate) + //{ + // //TODO: тут не проверен переход через выходные дни!!! Переход не используется, так как тут не рассчитываем NextRun. + // //В общем проверить, когда будем тестировать агента, что с датами все ок + // var esppSchedule = await GetEsppScheduleAsync(jobGroupId); + // var nextSchedule = GetNextSchedule(esppSchedule, referenceDate); - return nextSchedule; - } + // return nextSchedule; + //} private async Task GetEsppScheduleAsync(Guid jobGroupId) @@ -429,68 +429,68 @@ namespace PARR.DAL.TransformServices } - public DateTimeOffset GetNextDateForDistributionRun(DateTimeOffset lastRun, DistributionPeriodTypeEnum periodType, string distributionPeriod) - { - var nextRun = lastRun; + //public DateTimeOffset GetNextDateForDistributionRun(DateTimeOffset lastRun, DistributionPeriodTypeEnum periodType, string distributionPeriod) + //{ + // var nextRun = lastRun; - switch (periodType) - { - case (DistributionPeriodTypeEnum.Day): - nextRun = lastRun.AddDays(ParseInt(distributionPeriod)); - break; - case (DistributionPeriodTypeEnum.Month): - nextRun = lastRun.AddMonths(ParseInt(distributionPeriod)); - break; - case (DistributionPeriodTypeEnum.Year): - nextRun = lastRun.AddYears(ParseInt(distributionPeriod)); - break; - } + // switch (periodType) + // { + // case (DistributionPeriodTypeEnum.Day): + // nextRun = lastRun.AddDays(ParseInt(distributionPeriod)); + // break; + // case (DistributionPeriodTypeEnum.Month): + // nextRun = lastRun.AddMonths(ParseInt(distributionPeriod)); + // break; + // case (DistributionPeriodTypeEnum.Year): + // nextRun = lastRun.AddYears(ParseInt(distributionPeriod)); + // break; + // } - return nextRunModifierService.GetWorkDayAsync(nextRun).GetAwaiter().GetResult(); - } + // return nextRunModifierService.GetWorkDayAsync(nextRun).GetAwaiter().GetResult(); + //} - private DateTimeOffset GetPrevDateForDistributionRun(DateTimeOffset lastRun, DistributionPeriodTypeEnum periodType, string distributionPeriod) - { - switch (periodType) - { - case (DistributionPeriodTypeEnum.Day): - return lastRun.AddDays(-ParseInt(distributionPeriod)); + //private DateTimeOffset GetPrevDateForDistributionRun(DateTimeOffset lastRun, DistributionPeriodTypeEnum periodType, string distributionPeriod) + //{ + // switch (periodType) + // { + // case (DistributionPeriodTypeEnum.Day): + // return lastRun.AddDays(-ParseInt(distributionPeriod)); - case (DistributionPeriodTypeEnum.Month): - return lastRun.AddMonths(-ParseInt(distributionPeriod)); + // case (DistributionPeriodTypeEnum.Month): + // return lastRun.AddMonths(-ParseInt(distributionPeriod)); - case (DistributionPeriodTypeEnum.Year): - return lastRun.AddYears(-ParseInt(distributionPeriod)); - } + // case (DistributionPeriodTypeEnum.Year): + // return lastRun.AddYears(-ParseInt(distributionPeriod)); + // } - return lastRun; - } + // return lastRun; + //} - public async Task GetStartPeriodForDateAsync(Guid jobGroupId, DateTimeOffset date, DateTimeOffset referenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod) - { - var esppSchedule = await GetEsppScheduleAsync(jobGroupId); + //public async Task GetStartPeriodForDateAsync(Guid jobGroupId, DateTimeOffset date, DateTimeOffset referenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod) + //{ + // var esppSchedule = await GetEsppScheduleAsync(jobGroupId); - var currentStartPeriod = referenceDate; - var currentEndPeriod = GetNextDateForDistributionRun(currentStartPeriod, periodType, distributionPeriod); + // var currentStartPeriod = referenceDate; + // var currentEndPeriod = GetNextDateForDistributionRun(currentStartPeriod, periodType, distributionPeriod); - while (!(date >= currentStartPeriod && date < currentEndPeriod)) - { - if (date > currentEndPeriod) - { - currentStartPeriod = currentEndPeriod; - currentEndPeriod = GetNextDateForDistributionRun(currentStartPeriod, periodType, distributionPeriod); - } - else - { - currentEndPeriod = currentStartPeriod; - currentStartPeriod = GetPrevDateForDistributionRun(currentStartPeriod, periodType, distributionPeriod); - } - } + // while (!(date >= currentStartPeriod && date < currentEndPeriod)) + // { + // if (date > currentEndPeriod) + // { + // currentStartPeriod = currentEndPeriod; + // currentEndPeriod = GetNextDateForDistributionRun(currentStartPeriod, periodType, distributionPeriod); + // } + // else + // { + // currentEndPeriod = currentStartPeriod; + // currentStartPeriod = GetPrevDateForDistributionRun(currentStartPeriod, periodType, distributionPeriod); + // } + // } - return DateOnly.FromDateTime(currentStartPeriod.DateTime); - } + // return DateOnly.FromDateTime(currentStartPeriod.DateTime); + //} private int ParseInt(string value) @@ -507,12 +507,12 @@ namespace PARR.DAL.TransformServices } - private DistributionPeriodTypeEnum ParseDistributionPeriodType(string value) - { - var result = (DistributionPeriodTypeEnum)Enum.Parse(typeof(DistributionPeriodTypeEnum), value); + //private DistributionPeriodTypeEnum ParseDistributionPeriodType(string value) + //{ + // var result = (DistributionPeriodTypeEnum)Enum.Parse(typeof(DistributionPeriodTypeEnum), value); - return result; - } + // return result; + //} } } diff --git a/PARR.DAL/TransformServices/IEsppScheduleTransformService.cs b/PARR.DAL/TransformServices/IEsppScheduleTransformService.cs index 0364b88f..90f74fe9 100644 --- a/PARR.DAL/TransformServices/IEsppScheduleTransformService.cs +++ b/PARR.DAL/TransformServices/IEsppScheduleTransformService.cs @@ -1,20 +1,17 @@ -using PARR.Constants; -using PARR.DAL.DomainModels; - -namespace PARR.DAL.TransformServices +namespace PARR.DAL.TransformServices { /// /// Сервис трансформации расписания ЕСПП в дату/расписание /// public interface IEsppScheduleTransformService { - /// - /// Получить следующую дату согласно расписания - /// - /// - /// - /// - DateTimeOffset GetNextDate(EsppScheduleDto esppSchedule, DateTimeOffset lastRun); + ///// + ///// Получить следующую дату согласно расписания + ///// + ///// + ///// + ///// + //DateTimeOffset GetNextDate(EsppScheduleDto esppSchedule, DateTimeOffset lastRun); ///// ///// Получить расписание @@ -32,31 +29,31 @@ namespace PARR.DAL.TransformServices /// Task GetNextDateAsync(Guid jobGroupId, DateTimeOffset lastRun); - /// - /// Получить расписание по jobGroupId - /// - /// - /// - /// - Task> GetNextScheduleAsync(Guid jobGroupId, DateTimeOffset lastRun); + ///// + ///// Получить расписание по jobGroupId + ///// + ///// + ///// + ///// + //Task> GetNextScheduleAsync(Guid jobGroupId, DateTimeOffset lastRun); - /// - /// Получить следующую дату срабатывания в указанном периоде - /// - /// - /// - /// - /// - DateTimeOffset GetNextDateForDistributionRun(DateTimeOffset lastRun, DistributionPeriodTypeEnum periodType, string distributionPeriod); + ///// + ///// Получить следующую дату срабатывания в указанном периоде + ///// + ///// + ///// + ///// + ///// + //DateTimeOffset GetNextDateForDistributionRun(DateTimeOffset lastRun, DistributionPeriodTypeEnum periodType, string distributionPeriod); - /// - /// Получить дату начала периода распределения относительно опорной даты (Reference Date) - /// - /// - /// - /// - Task GetStartPeriodForDateAsync(Guid jobGroupId, DateTimeOffset date, DateTimeOffset refrenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod); + ///// + ///// Получить дату начала периода распределения относительно опорной даты (Reference Date) + ///// + ///// + ///// + ///// + //Task GetStartPeriodForDateAsync(Guid jobGroupId, DateTimeOffset date, DateTimeOffset refrenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod); } } diff --git a/PARR.DAL/TransformServices/INextRunModifierService.cs b/PARR.DAL/TransformServices/INextRunModifierService.cs index 2e36fb9c..1cd7103a 100644 --- a/PARR.DAL/TransformServices/INextRunModifierService.cs +++ b/PARR.DAL/TransformServices/INextRunModifierService.cs @@ -14,11 +14,11 @@ namespace PARR.DAL.TransformServices /// DateTimeOffset GetNextRunByAccountRobotTimeZone(DateTimeOffset nextRun); - /// - /// Получить РАБОЧИЙ день следующего срабатывания - /// - /// - /// - Task GetWorkDayAsync(DateTimeOffset nextRun); + ///// + ///// Получить РАБОЧИЙ день следующего срабатывания + ///// + ///// + ///// + //Task GetWorkDayAsync(DateTimeOffset nextRun); } } diff --git a/PARR.DAL/TransformServices/NextRunModifierService.cs b/PARR.DAL/TransformServices/NextRunModifierService.cs index 2b5e41aa..f6c438e4 100644 --- a/PARR.DAL/TransformServices/NextRunModifierService.cs +++ b/PARR.DAL/TransformServices/NextRunModifierService.cs @@ -29,40 +29,40 @@ namespace PARR.DAL.TransformServices } - public async Task GetWorkDayAsync(DateTimeOffset nextRun) - { - // получаем день относительно часового пояса МСК - var date = DateOnly.FromDateTime(DateResolver.IsCurrentDayRelativeMskTime(nextRun) ? nextRun.Date : nextRun.Date.AddDays(1)); + //public async Task GetWorkDayAsync(DateTimeOffset nextRun) + //{ + // // получаем день относительно часового пояса МСК + // var date = DateOnly.FromDateTime(DateResolver.IsCurrentDayRelativeMskTime(nextRun) ? nextRun.Date : nextRun.Date.AddDays(1)); - if (await weekendDayService.IsWorkDayAsync(date, true)) - { - //текущий nextRun рабочий день, возвращаем его - return nextRun; - } + // if (await weekendDayService.IsWorkDayAsync(date, true)) + // { + // //текущий nextRun рабочий день, возвращаем его + // return nextRun; + // } - // ищем следующий рабочий день, максимум 20 итераций, если за их кол-во не нашли рабочий, берём последний не рабочий - int count = 20; - while (count > 0) - { - date = date.AddDays(1); - var isWorkDay = await weekendDayService.IsWorkDayAsync(date, true); - if (isWorkDay) - break; // это рабочий день, выбираем его + // // ищем следующий рабочий день, максимум 20 итераций, если за их кол-во не нашли рабочий, берём последний не рабочий + // int count = 20; + // while (count > 0) + // { + // date = date.AddDays(1); + // var isWorkDay = await weekendDayService.IsWorkDayAsync(date, true); + // if (isWorkDay) + // break; // это рабочий день, выбираем его - count--; + // count--; - if (!isWorkDay && count == 0) - logger.LogWarning($"Не нашли рабочий день за 20 итераций, взяли последний нерабочий {date}"); - } + // if (!isWorkDay && count == 0) + // logger.LogWarning($"Не нашли рабочий день за 20 итераций, взяли последний нерабочий {date}"); + // } - // смотрим, если смещали из-за пояса МСК на день вперед, вычитаем этот день назад - if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun)) - date = date.AddDays(-1); + // // смотрим, если смещали из-за пояса МСК на день вперед, вычитаем этот день назад + // if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun)) + // date = date.AddDays(-1); - // считаем новый NextRun - var dayCount = date.DayNumber - DateOnly.FromDateTime(nextRun.Date).DayNumber; + // // считаем новый NextRun + // var dayCount = date.DayNumber - DateOnly.FromDateTime(nextRun.Date).DayNumber; - return nextRun.AddDays(dayCount); - } + // return nextRun.AddDays(dayCount); + //} } } diff --git a/PARR.JobAutoControl/JobAutoControlManager.cs b/PARR.JobAutoControl/JobAutoControlManager.cs index b6bd5e97..6ab362b6 100644 --- a/PARR.JobAutoControl/JobAutoControlManager.cs +++ b/PARR.JobAutoControl/JobAutoControlManager.cs @@ -75,17 +75,18 @@ namespace PARR.JobAutoControl InitiatorIp = null, InitiatorParrComponentId = Constants.ParrComponentsEnum.JobAutoControl } - }); + }).ToList(); - var msgStrList = msgList.Select(t => JsonSerializer.Serialize(t)); + //var msgStrList = msgList.Select(t => JsonSerializer.Serialize(t)); // отправляем задания в очередь template matcher`a - var sendResult = await mqService.SendAsync(mqSettings.TemplateMatcher, msgStrList.ToArray()); + //var sendResult = await mqService.SendAsync(mqSettings.TemplateMatcher, msgStrList.ToArray()); + var sendResult = await mqService.SendAsync(mqSettings.TemplateMatcher, msgList.ToList()); if (!sendResult.IsSuccess) - logger.LogError($"Ошибка при отправке сообщений ({msgStrList.Count()} шт.) в очередь."); + logger.LogError($"Ошибка при отправке сообщений ({msgList.Count()} шт.) в очередь."); else - logger.LogInformation($"Выполнена отправка сообщений в очередь, {msgStrList.Count()} шт."); + logger.LogInformation($"Выполнена отправка сообщений в очередь, {msgList.Count()} шт."); } } diff --git a/PARR.Master/Services/OrderMasterService.cs b/PARR.Master/Services/OrderMasterService.cs index a64e44aa..4a33c372 100644 --- a/PARR.Master/Services/OrderMasterService.cs +++ b/PARR.Master/Services/OrderMasterService.cs @@ -7,6 +7,7 @@ using PARR.DAL.Contracts; using PARR.DAL.Models; using PARR.DAL.Services.Interfaces; using PARR.Master.Settings; +using System.Text.Encodings.Web; using System.Text.Json; namespace PARR.Master.Services @@ -20,6 +21,11 @@ namespace PARR.Master.Services private readonly MqSettings mqSettings; private readonly IMqService mqService; + private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + public OrderMasterService( ILogger logger, IOrderService orderService, @@ -60,7 +66,7 @@ namespace PARR.Master.Services //находим наряды где статусы не равны, добавляем их в Rabbit var ordersWithStatusNotEqual = await GetOrdresWithStatusCodeNotEqualAsync(); - var objs = ordersWithStatusNotEqual.Select(t => JsonSerializer.Serialize(new OrderManageMq { OrderId = t.Id })); + var objs = ordersWithStatusNotEqual.Select(t => JsonSerializer.Serialize(new OrderManageMq { OrderId = t.Id }, jsonOptions)); logger.LogInformation($"Ищу наряды где статусы не равны. Найдено нарядов: {ordersWithStatusNotEqual.Count()}. Добавляю их в RabbitMQ."); diff --git a/PARR.NextRun/NextRunManager.cs b/PARR.NextRun/NextRunManager.cs index e679a509..cdab5375 100644 --- a/PARR.NextRun/NextRunManager.cs +++ b/PARR.NextRun/NextRunManager.cs @@ -4,10 +4,9 @@ using Microsoft.Extensions.Logging; using PARR.BLL.Services.Interfaces; using PARR.Common.Domain; using PARR.Constants; -using PARR.DAL.Models; +using PARR.DAL.NextRunServices; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; -using PARR.DAL.TransformServices; using PARR.NextRun.Settings; namespace PARR.NextRun @@ -41,14 +40,15 @@ namespace PARR.NextRun using (var scope = serviceProvider.CreateScope()) { //var appInWorkService = scope.ServiceProvider.GetService(); - var esppSchService = scope.ServiceProvider.GetService(); + //var esppSchService = scope.ServiceProvider.GetService(); var templateService = scope.ServiceProvider.GetService(); var jobGroupService = scope.ServiceProvider.GetService(); + var nextRunService = scope.ServiceProvider.GetService(); - if (templateService == null || esppSchService == null || jobGroupService == null) - throw new Exception($"Не смог получить серивс {nameof(ITemplateService)} или {nameof(IEsppScheduleTransformService)} или {nameof(IJobGroupService)}"); + if (templateService == null || nextRunService == null || jobGroupService == null) + throw new Exception($"Не смог получить серивс {nameof(ITemplateService)} или {nameof(INextRunService)} или {nameof(IJobGroupService)}"); - await HandlerAsync(templateService, esppSchService, jobGroupService); + await HandlerAsync(templateService, nextRunService, jobGroupService); } }, workerSettings.RepeatEvery); } @@ -58,7 +58,7 @@ namespace PARR.NextRun /// Рассчет следующей даты срабатываения /// /// - private async Task HandlerAsync(ITemplateService templateService, IEsppScheduleTransformService esppScheduleTransformService, IJobGroupService jobGroupService) + private async Task HandlerAsync(ITemplateService templateService, INextRunService nextRunService, IJobGroupService jobGroupService) { #region логика для групп у которых не включено автораспределение @@ -77,7 +77,8 @@ namespace PARR.NextRun foreach (var group in groups) { //получаем по каждой группе следующий nextRun и сравниваем с существующим, если не равны, то обновляем - var nextRun = await esppScheduleTransformService.GetNextDateAsync(group.Id, group.ReferenceDate); + //var nextRun = await esppScheduleTransformService.GetNextDateAsync(group.Id, group.ReferenceDate); + var nextRun = await nextRunService.GetNextRunForTemplateAsync(group.Id, false); // Загружаем только шаблоны текущей группы где nextRun в БД не равен расчетному @@ -109,7 +110,7 @@ namespace PARR.NextRun //todo: когда будет автораспределение, для него придумать логику как считать - + //TODO:!!! Написать логику для групп у которых включено автораспределение!!! #region old logic diff --git a/PARR.TemplateDistributor/ITemplateDistributor.cs b/PARR.TemplateDistributor/ITemplateDistributor.cs index c28dd8ac..e4842544 100644 --- a/PARR.TemplateDistributor/ITemplateDistributor.cs +++ b/PARR.TemplateDistributor/ITemplateDistributor.cs @@ -1,22 +1,14 @@ -using PARR.DAL.Models; +using PARR.BLL.Domain.Mq; namespace PARR.TemplateDistributor { public interface ITemplateDistributor { /// - /// Формирует расписание запуска для шаблонов относительно одной РР (без сохранения в БД), (реализует оба режима распределения РР) + /// Обновляет NextRun (сохраняет в БД) /// - /// - /// + /// /// - Task> DistributeTemplateAsync(List