feat(dal): NextRunService, GetNextRunForJobGroupWithAutoDistributionAsync - реализация, распределение шаблонов

This commit is contained in:
Mikhail Trubnikov
2026-01-21 12:19:27 +10:00
parent eb5bed5614
commit 5ad26742e6
4 changed files with 162 additions and 10 deletions

View File

@@ -1,4 +1,6 @@
namespace PARR.DAL.NextRunServices
using PARR.DAL.NextRunServices.Models;
namespace PARR.DAL.NextRunServices
{
public interface INextRunService
{
@@ -7,7 +9,7 @@
/// </summary>
/// <param name="jobGroupId"></param>
/// <returns></returns>
Task<List<(Guid TemplateId, DateTimeOffset NextRun)>> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId);
Task<List<TemplateNextRunResultDto>?> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId);
/// <summary>

View File

@@ -0,0 +1,5 @@
namespace PARR.DAL.NextRunServices.Models
{
internal record TemplateWithWorkGroupDto(Guid Id, DateTimeOffset? NextRun, string WorkGroup);
}

View File

@@ -1,6 +1,11 @@

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 +20,15 @@ namespace PARR.DAL.NextRunServices
private readonly IJobGroupService jobGroupService;
private readonly IEsppScheduleTransformService esppScheduleTransformService;
private readonly ITemplateDistributor templateDistributor;
private readonly IShortcodesService shortcodesService;
public NextRunService(
ILogger<NextRunService> logger,
ITemplateService templateService,
IJobGroupService jobGroupService,
IEsppScheduleTransformService esppScheduleTransformService,
ITemplateDistributor templateDistributor
ITemplateDistributor templateDistributor,
IShortcodesService shortcodesService
)
{
this.logger = logger;
@@ -29,14 +36,94 @@ namespace PARR.DAL.NextRunServices
this.jobGroupService = jobGroupService;
this.esppScheduleTransformService = esppScheduleTransformService;
this.templateDistributor = templateDistributor;
this.shortcodesService = shortcodesService;
}
public async Task<List<(Guid TemplateId, DateTimeOffset NextRun)>> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId)
public async Task<List<TemplateNextRunResultDto>?> 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<TemplateNextRunResultDto>();
if (jobGroup.DistributionConfig.IsGroupingByWorkGroup)
{
// Нужно группировать по РГ
// список шаблонов с полученной из шорткода РГ
var templatesWithWorkGroup = new List<TemplateWithWorkGroupDto>();
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;
}
@@ -81,5 +168,57 @@ namespace PARR.DAL.NextRunServices
return await esppScheduleTransformService.GetNextDateAsync(template.Job.Group.Id, template.Job.Group.ReferenceDate);
}
}
/// <summary>
/// Получить продолжительность в днях
/// </summary>
/// <param name="config"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Получить дату начала распределения
/// </summary>
/// <param name="referenceDate"></param>
/// <returns></returns>
private DateOnly GetDateStart(DateTimeOffset referenceDate)
{
var today = DateTime.UtcNow;
if (today < referenceDate)
return DateOnly.FromDateTime(referenceDate.Date);
else
return DateOnly.FromDateTime(today.Date);
}
}
}

View File

@@ -1,4 +1,5 @@
using PARR.DAL.NextRunServices.Models;
using PARR.DAL.NextRunServices;
using PARR.DAL.NextRunServices.Models;
using PARR.DAL.NextRunServices.Subservices;
namespace PARR.Test.NextRun
@@ -6,10 +7,12 @@ namespace PARR.Test.NextRun
internal class NextRunTest
{
private readonly ITemplateDistributor templateDistributor;
private readonly INextRunService nextRunService;
public NextRunTest(ITemplateDistributor templateDistributor)
public NextRunTest(ITemplateDistributor templateDistributor, INextRunService nextRunService)
{
this.templateDistributor = templateDistributor;
this.nextRunService = nextRunService;
}
int periodDays = 10;
@@ -17,8 +20,11 @@ namespace PARR.Test.NextRun
public async Task Test()
{
await DistributeTemplatesAsync();
//await DistributeTemplatesAsync();
//await GetValidNextRunForTemplateAsync();
var result = await nextRunService.GetNextRunForJobGroupWithAutoDistributionAsync(Guid.Parse("eadc5498-dba6-4f10-9b4b-a1653e3c3e61"));
}
/// <summary>