Merge branch 'dev' of gitlab.dvgd.oao.rzd:devptk/parr/parr_api into dev

This commit is contained in:
Mikhail Trubnikov
2026-02-26 08:46:08 +10:00
7 changed files with 74 additions and 30 deletions

View File

@@ -316,12 +316,12 @@ internal class UnitFilterService : IUnitFilterService
} }
// Выполняем промежуточный запрос для логирования // Выполняем промежуточный запрос для логирования
var intermediateResult = await query.Select(u => u.Id).ToListAsync(cancellationToken); //var intermediateResult = await query.Select(u => u.Id).ToListAsync(cancellationToken);
logger.LogDebug(" После фильтра #{Index}: осталось {Count} юнитов", filterIndex, intermediateResult.Count); //logger.LogDebug(" После фильтра #{Index}: осталось {Count} юнитов", filterIndex, intermediateResult.Count);
// Обновляем query для следующей итерации //// Обновляем query для следующей итерации
query = unitService.Get().AsNoTracking() //query = unitService.Get().AsNoTracking()
.Where(u => intermediateResult.Contains(u.Id)); // .Where(u => intermediateResult.Contains(u.Id));
} }
var result = await query.Select(u => u.Id).ToListAsync(cancellationToken); var result = await query.Select(u => u.Id).ToListAsync(cancellationToken);

View File

@@ -111,24 +111,40 @@ namespace PARR.DAL.Services.Implementations
public async Task<Guid?> ReserveUnusedTemplateAsync(Guid newUnitId, HistoryInitiator initiator) public async Task<Guid?> ReserveUnusedTemplateAsync(Guid newUnitId, HistoryInitiator initiator)
{ {
logger.LogDebug("Резервирую неиспользуемый шаблон для UnitId: {UnitId}", newUnitId); logger.LogDebug("Резервирую неиспользуемый шаблон с проверкой конфигураций роботов для UnitId: {UnitId}", newUnitId);
var sql = @" var sql = @"
UPDATE ""Templates"" UPDATE ""Templates""
SET ""StatusTypeId"" = @NewStatus, SET ""StatusTypeId"" = @NewStatus,
""DateModified"" = @DateModified, ""DateModified"" = @DateModified,
""InitiatorIp"" = @InitiatorIp, ""InitiatorIp"" = @InitiatorIp,
""InitiatorParrComponentId"" = @InitiatorComponent, ""InitiatorParrComponentId"" = @InitiatorComponent,
""InitiatorComment"" = @InitiatorComment ""InitiatorComment"" = @InitiatorComment
WHERE ""Id"" = ( WHERE ""Id"" = (
SELECT ""Id"" SELECT t.""Id""
FROM ""Templates"" FROM ""Templates"" t
WHERE ""StatusTypeId"" = @OldStatus WHERE t.""StatusTypeId"" = @OldStatus
AND ""UnitId"" != @NewUnitId AND t.""UnitId"" != @NewUnitId
ORDER BY ""DateCreated"" ASC AND EXISTS (
LIMIT 1 SELECT 1
) FROM ""RobotConfigurations"" rc
RETURNING ""Id"";"; WHERE rc.""TemplateId"" = t.""Id""
AND rc.""RobotCode"" = @RobotCode1
AND rc.""TaskStatusCode"" = @TaskStatus
AND rc.""RobotStatusCode"" = @RobotStatus
)
AND EXISTS (
SELECT 1
FROM ""RobotConfigurations"" rc
WHERE rc.""TemplateId"" = t.""Id""
AND rc.""RobotCode"" = @RobotCode2
AND rc.""TaskStatusCode"" = @TaskStatus
AND rc.""RobotStatusCode"" = @RobotStatus
)
ORDER BY t.""DateCreated"" ASC
LIMIT 1
)
RETURNING ""Id"";";
var parameters = new[] var parameters = new[]
{ {
@@ -141,7 +157,12 @@ namespace PARR.DAL.Services.Implementations
: DBNull.Value), : DBNull.Value),
new NpgsqlParameter("@InitiatorComment", initiator.InitiatorComment ?? (object)DBNull.Value), new NpgsqlParameter("@InitiatorComment", initiator.InitiatorComment ?? (object)DBNull.Value),
new NpgsqlParameter("@OldStatus", (int)TemplateStatusTypeEnum.Unused), new NpgsqlParameter("@OldStatus", (int)TemplateStatusTypeEnum.Unused),
new NpgsqlParameter("@NewUnitId", newUnitId) new NpgsqlParameter("@NewUnitId", newUnitId),
// Параметры для проверки конфигураций роботов
new NpgsqlParameter("@RobotCode1", 1),
new NpgsqlParameter("@RobotCode2", 2),
new NpgsqlParameter("@TaskStatus", 30),
new NpgsqlParameter("@RobotStatus", 44)
}; };
try try
@@ -159,7 +180,7 @@ namespace PARR.DAL.Services.Implementations
} }
else else
{ {
logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId}", newUnitId); logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId} (не найдено подходящих конфигураций роботов)", newUnitId);
} }
return reservedTemplateId; return reservedTemplateId;

View File

@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using PARR.BLL.Domain.Mq; using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces; using PARR.BLL.Services.Interfaces;
using PARR.Common.Domain; using PARR.Common.Domain;
@@ -29,9 +30,6 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
private const bool DefaultUsedTemplateState = false; private const bool DefaultUsedTemplateState = false;
private const bool DefaultUsedScheduleState = false; private const bool DefaultUsedScheduleState = false;
// Маска для неиспользуемых шаблонов — хардкод, недоступна из GUI
private const string UnusedTemplateNameMask = "%П-1%_НЕАКТУАЛЬНЫЕ_%ЭК%_%ТИКТАК%";
private readonly ILogger<SimpleTemplateSynchronizer> logger; private readonly ILogger<SimpleTemplateSynchronizer> logger;
private readonly IUnitFilterService unitFilterService; private readonly IUnitFilterService unitFilterService;
private readonly MqSettings mqSettings; private readonly MqSettings mqSettings;
@@ -45,6 +43,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
private readonly IMatchingStatusService matchingStatusService; private readonly IMatchingStatusService matchingStatusService;
private readonly SettingsFromDb settingsFromDb; private readonly SettingsFromDb settingsFromDb;
private readonly INextRunService nextRunService; private readonly INextRunService nextRunService;
private readonly IOptions<TemplateSettings> templateSettings;
public SimpleTemplateSynchronizer( public SimpleTemplateSynchronizer(
ILogger<SimpleTemplateSynchronizer> logger, ILogger<SimpleTemplateSynchronizer> logger,
@@ -65,7 +64,8 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
ITemplateUpdaterMqSender templateUpdaterMqSender, ITemplateUpdaterMqSender templateUpdaterMqSender,
IMatchingStatusService matchingStatusService, IMatchingStatusService matchingStatusService,
SettingsFromDb settingsFromDb, SettingsFromDb settingsFromDb,
INextRunService nextRunService INextRunService nextRunService,
IOptions<TemplateSettings> templateSettings
) )
{ {
this.logger = logger; this.logger = logger;
@@ -81,6 +81,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
this.matchingStatusService = matchingStatusService; this.matchingStatusService = matchingStatusService;
this.settingsFromDb = settingsFromDb; this.settingsFromDb = settingsFromDb;
this.nextRunService = nextRunService; this.nextRunService = nextRunService;
this.templateSettings = templateSettings;
} }
public async Task SyncTemplatesForJobAsync(Guid jobId, HistoryInitiator initiator) public async Task SyncTemplatesForJobAsync(Guid jobId, HistoryInitiator initiator)
@@ -552,7 +553,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer
MinValueRelationships = unusedJob.MinValueRelationships, MinValueRelationships = unusedJob.MinValueRelationships,
MaxValueRelationships = unusedJob.MaxValueRelationships, MaxValueRelationships = unusedJob.MaxValueRelationships,
IsParentRelationships = unusedJob.IsParentRelationships, IsParentRelationships = unusedJob.IsParentRelationships,
TemplateNameMask = UnusedTemplateNameMask, TemplateNameMask = templateSettings.Value.UnusedTemplateNameMask,
WorkGroupMask = unusedJob.WorkGroupMask, WorkGroupMask = unusedJob.WorkGroupMask,
ResponseAreaMask = unusedJob.ResponseAreaMask, ResponseAreaMask = unusedJob.ResponseAreaMask,
TnkId = unusedJob.TnkId, TnkId = unusedJob.TnkId,

View File

@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using PARR.BLL.Domain.Mq; using PARR.BLL.Domain.Mq;
using PARR.Common.Domain; using PARR.Common.Domain;
using PARR.Constants; using PARR.Constants;
@@ -8,6 +9,7 @@ using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Job;
using PARR.TemplateMatcher.Services.Interfaces; using PARR.TemplateMatcher.Services.Interfaces;
using PARR.TemplateMatcher.Settings;
namespace PARR.TemplateMatcher.Services.Implementations; namespace PARR.TemplateMatcher.Services.Implementations;
@@ -22,6 +24,7 @@ internal class TemplateDeactivator : ITemplateDeactivator
private readonly ITemplateNameNormalizer namenormalizer; private readonly ITemplateNameNormalizer namenormalizer;
private readonly ITemplateUpdaterMqSender sender; private readonly ITemplateUpdaterMqSender sender;
private readonly SettingsFromDb settingsFromDb; private readonly SettingsFromDb settingsFromDb;
private readonly IOptions<TemplateSettings> templateSettings;
public TemplateDeactivator( public TemplateDeactivator(
ILogger<TemplateDeactivator> logger, ILogger<TemplateDeactivator> logger,
@@ -29,7 +32,8 @@ internal class TemplateDeactivator : ITemplateDeactivator
IJobService jobService, IJobService jobService,
ITemplateNameNormalizer namenormalizer, ITemplateNameNormalizer namenormalizer,
ITemplateUpdaterMqSender sender, ITemplateUpdaterMqSender sender,
SettingsFromDb settingsFromDb SettingsFromDb settingsFromDb,
IOptions<TemplateSettings> templateSettings
) )
{ {
this.logger = logger; this.logger = logger;
@@ -38,6 +42,7 @@ internal class TemplateDeactivator : ITemplateDeactivator
this.namenormalizer = namenormalizer; this.namenormalizer = namenormalizer;
this.sender = sender; this.sender = sender;
this.settingsFromDb = settingsFromDb; this.settingsFromDb = settingsFromDb;
this.templateSettings = templateSettings;
} }
public async Task<bool> DeactivateTemplateAsync(Template template, HistoryInitiator initiator) public async Task<bool> DeactivateTemplateAsync(Template template, HistoryInitiator initiator)
@@ -70,12 +75,15 @@ internal class TemplateDeactivator : ITemplateDeactivator
.ThenInclude(g => g!.GroupType) .ThenInclude(g => g!.GroupType)
.FirstOrDefaultAsync(j => j.Id == settingsFromDb.JobIdForUnusedTemplates); .FirstOrDefaultAsync(j => j.Id == settingsFromDb.JobIdForUnusedTemplates);
if (unusedJob == null) if (unusedJob == null)
{ {
logger.LogError("Job для деактивированных шаблонов не найден."); logger.LogError("Job для деактивированных шаблонов не найден.");
return false; return false;
} }
unusedJob.TemplateNameMask = templateSettings.Value.UnusedTemplateNameMask;
// === Создаём временный Template для нормализации имени === // === Создаём временный Template для нормализации имени ===
var tempTemplateForName = new Template var tempTemplateForName = new Template
{ {
@@ -96,7 +104,7 @@ internal class TemplateDeactivator : ITemplateDeactivator
TemplateId = template.Id, TemplateId = template.Id,
JobId = unusedJob.Id, JobId = unusedJob.Id,
UnitId = template.UnitId, UnitId = template.UnitId,
Name = expectedName + "_" + DateTimeOffset.UtcNow.ToUnixTimeSeconds(), Name = expectedName,
IsActiveTemplate = DefaultUnusedTemplateState, IsActiveTemplate = DefaultUnusedTemplateState,
IsActiveSchedule = DefaultUnusedScheduleState, IsActiveSchedule = DefaultUnusedScheduleState,
LastRun = template.LastRun, LastRun = template.LastRun,

View File

@@ -0,0 +1,7 @@
namespace PARR.TemplateMatcher.Settings
{
internal class TemplateSettings
{
public string UnusedTemplateNameMask { get; set; } = "%П-1%_НЕАКТУАЛЬНЫЕ_%ЭК%_%ТИКТАК%";
}
}

View File

@@ -20,6 +20,10 @@ namespace PARR.TemplateMatcher
configuration.GetSection(nameof(MqSettings)).Bind(mqSettings); configuration.GetSection(nameof(MqSettings)).Bind(mqSettings);
services.AddSingleton(mqSettings); services.AddSingleton(mqSettings);
var templateSettings = new TemplateSettings();
configuration.GetSection(nameof(TemplateSettings)).Bind(templateSettings);
services.AddSingleton(templateSettings);
services.AddTransient<IMqTemplateMatcher, MqTemplateMatcher>(); services.AddTransient<IMqTemplateMatcher, MqTemplateMatcher>();
services.AddTransient<IJobValidatorService, JobValidatorService>(); services.AddTransient<IJobValidatorService, JobValidatorService>();
services.AddTransient<IJobGroupValidatorService, JobGroupValidatorService>(); services.AddTransient<IJobGroupValidatorService, JobGroupValidatorService>();

View File

@@ -44,5 +44,8 @@
}, },
"GroupedShortcodeCacheSettings": { "GroupedShortcodeCacheSettings": {
"ValueTtl": "00:20:00" "ValueTtl": "00:20:00"
},
"TemplateSettings": {
"UnusedTemplateNameMask": "%П-1%_НЕАКТУАЛЬНЫЕ_%ЭК%_%ТИКТАК%"
} }
} }