refactor(templateDistributor): добавлены комментарии

This commit is contained in:
Mikhail Kuznetsov
2024-07-25 14:05:00 +10:00
parent 70d96cb88f
commit 7220bdd8af
4 changed files with 78 additions and 72 deletions

3
.gitignore vendored
View File

@@ -33,6 +33,9 @@ bld/
[Ll]og/ [Ll]og/
[Ll]ogs/ [Ll]ogs/
# VS Code
.vscode/
# Visual Studio 2015/2017 cache/options directory # Visual Studio 2015/2017 cache/options directory
.vs/ .vs/
# Uncomment if you have tasks that create the project's static files in wwwroot # Uncomment if you have tasks that create the project's static files in wwwroot

View File

@@ -13,7 +13,6 @@ namespace PARR.TemplateDistributor
private readonly ILogger<TemplateDistributor> logger; private readonly ILogger<TemplateDistributor> logger;
private readonly ITemplateService templateService; private readonly ITemplateService templateService;
private readonly IApplicationsInWorkService applicationsInWorkService; private readonly IApplicationsInWorkService applicationsInWorkService;
private readonly IEsppSchTypeScheduleService esppSchTypeScheduleService;
private readonly ICalendarService calendarService; private readonly ICalendarService calendarService;
private readonly IEsppScheduleTransformService esppScheduleTransformService; private readonly IEsppScheduleTransformService esppScheduleTransformService;
private readonly IWeekendDayService weekendDayService; private readonly IWeekendDayService weekendDayService;
@@ -22,7 +21,6 @@ namespace PARR.TemplateDistributor
ILogger<TemplateDistributor> logger, ILogger<TemplateDistributor> logger,
ITemplateService templateService, ITemplateService templateService,
IApplicationsInWorkService applicationsInWorkService, IApplicationsInWorkService applicationsInWorkService,
IEsppSchTypeScheduleService esppSchTypeScheduleService,
ICalendarService calendarService, ICalendarService calendarService,
IEsppScheduleTransformService esppScheduleTransformService, IEsppScheduleTransformService esppScheduleTransformService,
IWeekendDayService weekendDayService IWeekendDayService weekendDayService
@@ -31,7 +29,6 @@ namespace PARR.TemplateDistributor
this.logger = logger; this.logger = logger;
this.templateService = templateService; this.templateService = templateService;
this.applicationsInWorkService = applicationsInWorkService; this.applicationsInWorkService = applicationsInWorkService;
this.esppSchTypeScheduleService = esppSchTypeScheduleService;
this.calendarService = calendarService; this.calendarService = calendarService;
this.esppScheduleTransformService = esppScheduleTransformService; this.esppScheduleTransformService = esppScheduleTransformService;
this.weekendDayService = weekendDayService; this.weekendDayService = weekendDayService;
@@ -40,57 +37,45 @@ namespace PARR.TemplateDistributor
public async Task UpdateScheduleAsync(Guid applicationInWorkId) public async Task UpdateScheduleAsync(Guid applicationInWorkId)
{ {
// все шаблоны по applicationInWorkId
// группирует по РР
// -> DistributeTemplateForPeriodAsync
// сохранить в БД
//applicationInWorkId = Guid.Parse("bdfefd77-bce3-4f62-a484-5042c06f4467");
var appInWork = await applicationsInWorkService.GetAsync(applicationInWorkId); var appInWork = await applicationsInWorkService.GetAsync(applicationInWorkId);
// .Include(aiw => aiw.EsppSchValues)
// .ThenInclude(esv => esv.EsppSchTypeValue)
// .ThenInclude(etv => etv!.DistributionPeriod)
// .FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
var templates = await templateService.Get() var templates = await templateService.Get()
.Include(t => t.Host) .Include(t => t.Host)
.ThenInclude(h => h.WorkGroup) .ThenInclude(h => h.WorkGroup)
.Where(t => t.ApplicationInWorkId == applicationInWorkId) .Where(t => t.ApplicationInWorkId == applicationInWorkId && t.Host!.WorkGroupId != null)
.ToListAsync(); .ToListAsync();
//Группируем шаблоны по рабочим группам
var workGroupsWithTemplates = templates.GroupBy(t => t.Host!.WorkGroupId); var workGroupsWithTemplates = templates.GroupBy(t => t.Host!.WorkGroupId);
foreach (var workGroupWithTemplates in workGroupsWithTemplates) foreach (var workGroupWithTemplates in workGroupsWithTemplates)
{ {
var wgId = workGroupWithTemplates.Key ?? Guid.NewGuid();//TODO сделать правильно var wgId = (Guid)workGroupWithTemplates.Key!;
var values = workGroupWithTemplates.ToList(); var values = workGroupWithTemplates.ToList();
if (!values.Any()) //Обновляем сразу время при необходимости, так как дальше будем работать только с датой
continue; var timesList = values.Select(t => t.NextRun.TimeOfDay).Distinct().ToList();
if (timesList.Count() > 1 || (timesList.Count() == 1 && timesList[0] != appInWork!.ReferenceDate.TimeOfDay))
//Обновляем сразу время при необходимости
values.ForEach(t =>
{ {
if (t.NextRun.TimeOfDay != appInWork!.ReferenceDate.TimeOfDay) values.ForEach(t =>
//t.NextRun = new DateTimeOffset(t.NextRun.DateTime, new TimeSpan(//(appInWork!.ReferenceDate.Hour, appInWork!.ReferenceDate.Minute, appInWork!.ReferenceDate.Second)); {
t.NextRun = new DateTimeOffset(t.NextRun.Year, t.NextRun.Month, t.NextRun.Day, if (t.NextRun.TimeOfDay != appInWork!.ReferenceDate.TimeOfDay)
appInWork!.ReferenceDate.Hour, appInWork!.ReferenceDate.Minute, appInWork!.ReferenceDate.Second, t.NextRun = new DateTimeOffset(t.NextRun.Year, t.NextRun.Month, t.NextRun.Day,
new TimeSpan(0, 0, 0)); appInWork!.ReferenceDate.Hour, appInWork!.ReferenceDate.Minute, appInWork!.ReferenceDate.Second,
}); new TimeSpan(0, 0, 0));
});
if (!await applicationsInWorkService.CommitAsync()) if (!await templateService.CommitAsync())
{ {
logger.LogError($"Ошибка записи изменений в БД при актуализации времени NextRun шаблонов"); logger.LogError($"Ошибка записи изменений в БД при актуализации времени NextRun шаблонов РР({applicationInWorkId})");
return; return;
}
} }
var distrTemplates = await DistributeTemplateAsync(new List<Template>(), applicationInWorkId, wgId);
var distrTemplates = await DistributeTemplateAsync(values, applicationInWorkId, wgId);
if (distrTemplates.Any()) if (distrTemplates.Any())
if (!await applicationsInWorkService.CommitAsync()) if (!await templateService.CommitAsync())
logger.LogError($"Ошибка записи изменений в БД при перераспределении NextRun шаблонов"); logger.LogError($"Ошибка записи изменений в БД при перераспределении NextRun шаблонов РР({applicationInWorkId})");
} }
} }
@@ -101,12 +86,12 @@ namespace PARR.TemplateDistributor
.Include(aiw => aiw.EsppSchValues) .Include(aiw => aiw.EsppSchValues)
.ThenInclude(esv => esv.EsppSchTypeValue) .ThenInclude(esv => esv.EsppSchTypeValue)
.ThenInclude(etv => etv!.DistributionPeriod) .ThenInclude(etv => etv!.DistributionPeriod)
.FirstOrDefaultAsync(t => t.Id == applicationInWorkId); .FirstAsync(t => t.Id == applicationInWorkId);
var refDate = appInWork!.ReferenceDate; var refDate = appInWork.ReferenceDate;
//Проверяем наличие распределения РР на период //Проверяем наличие распределения РР на период
if (appInWork!.IsAutoDistributionEnabled) if (appInWork.IsAutoDistributionEnabled)
{ {
var existingTemplates = await templateService.Get() var existingTemplates = await templateService.Get()
.Include(t => t.Host) .Include(t => t.Host)
@@ -114,10 +99,11 @@ namespace PARR.TemplateDistributor
.ToListAsync(); .ToListAsync();
//Удалим из входных шаблонов уже существующие в БД //Удалим из входных шаблонов уже существующие в БД
//TODO: сделать селект повторяющихся шаблонов, написать их в варнинг и потом удалить
templates.RemoveAll(t => existingTemplates.Any(et => et.Id == t.Id)); templates.RemoveAll(t => existingTemplates.Any(et => et.Id == t.Id));
//Если распределенная РР получаем начало //Если распределенная РР получаем начало
var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod; var period = appInWork.EsppSchValues.First()!.EsppSchTypeValue!.DistributionPeriod;
var periodType = ParseDistributionPeriodType(period!.Type); var periodType = ParseDistributionPeriodType(period!.Type);
var workDays = await GetWorkDaysAsync(appInWork); var workDays = await GetWorkDaysAsync(appInWork);
@@ -162,7 +148,7 @@ namespace PARR.TemplateDistributor
return templates; return templates;
#region comments
//var d = new Dictionary<DateOnly, List<Template>>(); //var d = new Dictionary<DateOnly, List<Template>>();
//foreach (var wd in workDays) //foreach (var wd in workDays)
@@ -233,6 +219,8 @@ namespace PARR.TemplateDistributor
// } // }
// } // }
//} //}
#endregion
} }
else else
templates.ForEach(t => t.NextRun = appInWork!.ReferenceDate); templates.ForEach(t => t.NextRun = appInWork!.ReferenceDate);
@@ -240,7 +228,12 @@ namespace PARR.TemplateDistributor
return templates; return templates;
} }
private async Task<List<DateOnly>> GetWorkDaysAsync(ApplicationsInWork appInWork) /// <summary>
/// Получить список рабочих дней из календаря и перенести прошедшие даты на следующий период по РР
/// </summary>
/// <param name="appInWork"></param>
/// <returns></returns>
public async Task<List<DateOnly>> GetWorkDaysAsync(ApplicationsInWork appInWork)
{ {
var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod; var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod;
@@ -255,6 +248,7 @@ namespace PARR.TemplateDistributor
wd.Year, wd.Month, wd.Day, wd.Year, wd.Month, wd.Day,
appInWork.ReferenceDate.Hour, appInWork.ReferenceDate.Minute, appInWork.ReferenceDate.Second, appInWork.ReferenceDate.Hour, appInWork.ReferenceDate.Minute, appInWork.ReferenceDate.Second,
new TimeSpan(0, 0, 0)); new TimeSpan(0, 0, 0));
if (wrokDateTimeOffset < DateTimeOffset.UtcNow) if (wrokDateTimeOffset < DateTimeOffset.UtcNow)
{ {
wrokDateTimeOffset = esppScheduleTransformService.GetNextDateForDistributionRun(wrokDateTimeOffset, periodType, period.Duration); wrokDateTimeOffset = esppScheduleTransformService.GetNextDateForDistributionRun(wrokDateTimeOffset, periodType, period.Duration);
@@ -265,16 +259,19 @@ namespace PARR.TemplateDistributor
return result; return result;
} }
/// <summary>
/// Проверить соответствие распределения существующих шаблонов нововму плану.
/// На выходе получаем шаблоны, которым требуется изменить дату следующего запуска.
/// </summary>
/// <param name="distributionPlan"></param>
/// <param name="templates"></param>
/// <returns></returns>
private List<Template> GetTemplatesToDistribute(ref Dictionary<DateOnly, int> distributionPlan, List<Template> templates) private List<Template> GetTemplatesToDistribute(ref Dictionary<DateOnly, int> distributionPlan, List<Template> templates)
{ {
var result = new List<Template>(); var result = new List<Template>();
foreach (var wd in distributionPlan) foreach (var wd in distributionPlan)
{ {
//if (wd.Value < 1)
// continue;
var templatesInWd = templates.Where(t => DateOnly.FromDateTime(t.NextRun.DateTime) == wd.Key).ToList(); var templatesInWd = templates.Where(t => DateOnly.FromDateTime(t.NextRun.DateTime) == wd.Key).ToList();
var templatesToDistribute = templatesInWd.Skip(wd.Value).Take(templatesInWd.Count - wd.Value).ToList(); var templatesToDistribute = templatesInWd.Skip(wd.Value).Take(templatesInWd.Count - wd.Value).ToList();
@@ -303,48 +300,51 @@ namespace PARR.TemplateDistributor
private Dictionary<DateOnly, int> GetDistributionPlan(List<DateOnly> workDays, int templateCount) private Dictionary<DateOnly, int> GetDistributionPlan(List<DateOnly> workDays, int templateCount)
{ {
var d = new Dictionary<DateOnly, int>(); var result = new Dictionary<DateOnly, int>();
//Заполняем будующий план датами из полученных на входе данных
foreach (var wd in workDays) foreach (var wd in workDays)
{ {
var workDateTimeOffset = new DateOnly(wd.Year, wd.Month, wd.Day); var workDate = new DateOnly(wd.Year, wd.Month, wd.Day);
d.Add(workDateTimeOffset, 0); result.Add(workDate, 0);
} }
var templateDistributed = 0; var templateDistributedCount = 0;//количество распределённых на текущий момент шаблонов
if (templateCount >= workDays.Count) //Если количество шаблонов больше количества рабочих дней, то сразу распределяем их равным количеством по всем рабочим дням
if (templateDistributedCount >= workDays.Count)
{ {
//количеством шаблонов на один рабочий день
var mainPartTemplateCountToDistribute = templateCount / workDays.Count; var mainPartTemplateCountToDistribute = templateCount / workDays.Count;
foreach (var item in d)
{
d[item.Key] = mainPartTemplateCountToDistribute;
templateDistributed += mainPartTemplateCountToDistribute; //перебираем рабочие дня и записываем количество шаблонов
foreach (var item in result)
{
result[item.Key] = mainPartTemplateCountToDistribute;
templateDistributedCount += mainPartTemplateCountToDistribute;
} }
} }
var daysBetweenTemplates = (double)workDays.Count / (templateCount % workDays.Count);//количество дней между шаблонами, если распределить их равномерно
var currentStepBetweenTemplates = (double)Math.Floor(daysBetweenTemplates);//инициализация шага перехода между датами запуска двух шаблонов
var balance = (double)daysBetweenTemplates - Math.Floor(currentStepBetweenTemplates);//остаток между датами, потому что мы берём целые дни, его нужно учесть в следующей итирации
var currentDayIndex = 0;//инициализация индекса даты словаря рабочих дней
var templatesPerWorkDay = (double)workDays.Count / (templateCount % workDays.Count); while (templateDistributedCount < templateCount)
var currentStep = (double)Math.Floor(templatesPerWorkDay);//??????? точно double?
var balance = (double)templatesPerWorkDay - Math.Floor(currentStep);
var currentIndex = 0;
while (templateDistributed < templateCount)
{ {
if (currentStep > 0) //лишняя проверка так как шагом ранее мы распределям шаблоны равным количеством и currentStepBetweenTemplates не может быть меньше одного дня
{ //if (currentStepBetweenTemplates > 0)
d[d.ElementAt(currentIndex).Key] += 1; //{
templateDistributed++; result[result.ElementAt(currentDayIndex).Key] += 1;
currentIndex += (int)Math.Floor(currentStep); templateDistributedCount++;
currentDayIndex += (int)Math.Floor(currentStepBetweenTemplates);
//}
currentStepBetweenTemplates = daysBetweenTemplates + balance;
} balance = daysBetweenTemplates - currentStepBetweenTemplates;
currentStep = templatesPerWorkDay + balance;
balance = templatesPerWorkDay - currentStep;
} }
return d; return result;
} }
} }

View File

@@ -19,5 +19,6 @@
<ProjectReference Include="..\PARR.BLL\PARR.BLL.csproj" /> <ProjectReference Include="..\PARR.BLL\PARR.BLL.csproj" />
<ProjectReference Include="..\PARR.DAL\PARR.DAL.csproj" /> <ProjectReference Include="..\PARR.DAL\PARR.DAL.csproj" />
<ProjectReference Include="..\PARR.EsppApi\PARR.EsppApi.csproj" /> <ProjectReference Include="..\PARR.EsppApi\PARR.EsppApi.csproj" />
<ProjectReference Include="..\PARR.TemplateDistributor\PARR.TemplateDistributor.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -3,6 +3,7 @@ using PARR.EsppApi;
using PARR.DAL; using PARR.DAL;
using PARR.Test; using PARR.Test;
using Serilog; using Serilog;
using PARR.TemplateDistributor;
IHost host = Host.CreateDefaultBuilder(args) IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => .ConfigureServices((hostContext, services) =>
@@ -10,6 +11,7 @@ IHost host = Host.CreateDefaultBuilder(args)
services.InstallEsppApiServices(hostContext.Configuration); services.InstallEsppApiServices(hostContext.Configuration);
services.InstallBllServices(hostContext.Configuration); services.InstallBllServices(hostContext.Configuration);
services.InstallDalServices(hostContext.Configuration); services.InstallDalServices(hostContext.Configuration);
services.InstallTemplateDistributorSerivces(hostContext.Configuration);
services.AddHostedService<Worker>(); services.AddHostedService<Worker>();
}) })