From 497d241caf7681ee4baf8d387ebeb280232ec2e9 Mon Sep 17 00:00:00 2001 From: Mikhail Kuznetsov Date: Tue, 14 Jul 2026 14:55:49 +1000 Subject: [PATCH] =?UTF-8?q?feat(aihitRelationshipsSyncer):=20=D0=94=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=80=D0=B5=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20MinRelationshipsTh?= =?UTF-8?q?resholdPct=20=D0=B4=D0=BB=D1=8F=20=D0=B7=D0=B0=D1=89=D0=B8?= =?UTF-8?q?=D1=82=D1=8B=20=D0=B1=D0=B0=D0=B7=D1=8B=20=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=BE=D1=82=20=D0=BF=D0=BE=D1=82=D0=B5?= =?UTF-8?q?=D1=80=D0=B8=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B5=D0=B9=20=D0=AD?= =?UTF-8?q?=D0=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RelationshipsSyncService.cs | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/PARR.AIHITRelationshipsSyncer/Services/Implementations/RelationshipsSyncService.cs b/PARR.AIHITRelationshipsSyncer/Services/Implementations/RelationshipsSyncService.cs index 25e6074b..3b6bfd4f 100644 --- a/PARR.AIHITRelationshipsSyncer/Services/Implementations/RelationshipsSyncService.cs +++ b/PARR.AIHITRelationshipsSyncer/Services/Implementations/RelationshipsSyncService.cs @@ -2,9 +2,9 @@ using Microsoft.Extensions.Logging; using PARR.AIHITRelationshipsSyncer.Models; using PARR.AIHITRelationshipsSyncer.Services.Interfaces; -using PARR.AIHITRelationshipsSyncer.Settings; using PARR.Core.Repositories.Interfaces.Unit; using PARR.Domain.Entities.Unit; +using PARR.Domain.Settings; namespace PARR.AIHITRelationshipsSyncer.Services.Implementations { @@ -12,25 +12,56 @@ namespace PARR.AIHITRelationshipsSyncer.Services.Implementations { private readonly ILogger logger; private readonly IUnitRepository unitService; - private readonly WorkerSettings workerSettings; + private readonly SettingsFromDb _settingsFromDb; public RelationshipsSyncService( ILogger logger, IUnitRepository unitService, - WorkerSettings workerSettings + SettingsFromDb settingsFromDb ) { this.logger = logger; this.unitService = unitService; - this.workerSettings = workerSettings; + _settingsFromDb = settingsFromDb; } public async Task SyncAsync(List aihitdata) { + // 1. Сначала фильтруем и нормализуем входящий мусор var validPairs = ValidateInput(aihitdata); + + // Если пришел пустой список, то и проверять порог нет смысла (лог уже записан внутри) if (!validPairs.Any()) return; + // 2. FAIL-FAST: Быстро узнаем общее число связей в БД без выкачивания самих данных + int previousCount = await unitService.Get() + .SelectMany(u => u.ChildUnits) + .CountAsync(); + + // 3. SAFEGUARD COMPLIANCE: Проверяем защитный порог падения данных + if (previousCount > 0) + { + // 1. Считаем в decimal с абсолютной точностью + decimal exactPercentage = ((decimal)validPairs.Count / previousCount) * 100; + + // 2. Округляем до 1 знака после запятой (например, 96.98% -> 97.0%) + // Это защитит от ложных срабатываний из-за пары недостающих связей на больших объемах + decimal currentPercentage = Math.Round(exactPercentage, 1, MidpointRounding.AwayFromZero); + + // 3. Строгое сравнение (<) гарантирует пропуск при ровно 97% и работу "0" как выключателя + if (currentPercentage < _settingsFromDb.MinRelationshipsThresholdPct) + { + logger.LogWarning( + "Синхронизация отменена: количество полученных связей ниже порогового значения! " + + "Получено: {CurrentCount} ({CurrentPercentage:F1}%), ожидалось >= {Threshold}% от прошлого объема ({PreviousCount}).", + validPairs.Count, currentPercentage, _settingsFromDb.MinRelationshipsThresholdPct, previousCount); + + return; + } + } + + // 4. HAPPY PATH: Если проверка пройдена, выполняем тяжелую работу var sourceUnitNames = ExtractUnitNames(validPairs); var existingUnits = await GetOrCreateUnitsAsync(sourceUnitNames); @@ -42,6 +73,7 @@ namespace PARR.AIHITRelationshipsSyncer.Services.Implementations await FinalCommitAsync(toRemove.Count, toAdd.Count); } + private List<(string Parent, string Child)> ValidateInput(List data) { if (data == null || data.Count == 0)