From 4cc1269554e2afb5885853ed8ed480573569b1bc Mon Sep 17 00:00:00 2001 From: Mikhail Kuznetsov Date: Tue, 21 Apr 2026 14:36:24 +1000 Subject: [PATCH] =?UTF-8?q?feat(dal):=20=D0=A0=D0=B5=D0=B7=D1=83=D0=BB?= =?UTF-8?q?=D1=8C=D1=82=D0=B0=D1=82=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B?= =?UTF-8?q?=20ShortcodesService=20=D0=B2=D0=B5=D1=81=D1=8C=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20?= =?UTF-8?q?=D0=B2=20Redis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/CachedGroupedShortCode.cs | 10 ---- .../Shortcodes/ShortcodesService.cs | 47 ++++++++++++++----- PARR.Domain/Cache/Models/GroupedShortсode.cs | 21 +++++++++ PARR.Domain/Cache/Models/ShortcodesResult.cs | 21 +++++++++ .../SimpleTemplateSynchronizer.cs | 2 +- 5 files changed, 77 insertions(+), 24 deletions(-) delete mode 100644 PARR.DAL/DomainServices/Shortcodes/Models/CachedGroupedShortCode.cs create mode 100644 PARR.Domain/Cache/Models/GroupedShortсode.cs create mode 100644 PARR.Domain/Cache/Models/ShortcodesResult.cs diff --git a/PARR.DAL/DomainServices/Shortcodes/Models/CachedGroupedShortCode.cs b/PARR.DAL/DomainServices/Shortcodes/Models/CachedGroupedShortCode.cs deleted file mode 100644 index 6d9e244d..00000000 --- a/PARR.DAL/DomainServices/Shortcodes/Models/CachedGroupedShortCode.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace PARR.DAL.DomainServices.Shortcodes.Models -{ - internal class CachedGroupedShortCode - { - public string Value { get; set; } = string.Empty; - public DateTimeOffset Timestamp { get; set; } - public string? Source { get; set; } = "ShortcodesService"; - public int Version { get; set; } = 1; - } -} diff --git a/PARR.DAL/DomainServices/Shortcodes/ShortcodesService.cs b/PARR.DAL/DomainServices/Shortcodes/ShortcodesService.cs index 53e8223a..bda65659 100644 --- a/PARR.DAL/DomainServices/Shortcodes/ShortcodesService.cs +++ b/PARR.DAL/DomainServices/Shortcodes/ShortcodesService.cs @@ -3,13 +3,13 @@ using Microsoft.Extensions.Logging; using PARR.Core.Common.Interfaces; using PARR.DAL.Contracts; using PARR.DAL.DomainModels; -using PARR.DAL.DomainServices.Shortcodes.Models; using PARR.DAL.DomainServices.UnitFilterService; using PARR.DAL.Models; using PARR.DAL.Models.Job; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Unit; +using PARR.Domain.Cache.Models; using PARR.Domain.Common.Template; using PARR.Domain.Enums; using System.Runtime.CompilerServices; @@ -130,6 +130,19 @@ namespace PARR.DAL.DomainServices.Shortcodes var callerName = caller ?? "Unknown"; + // Ключ: shortcodes_result_{TemplateIdN}_{Hash(str)} + var cacheKey = cacheService.GetKey( + new[] { "shortcodes", "result", template.Id.ToString("N") }, + new[] { str } + ); + + var cachedResult = await cacheService.GetCachedDataAsync(cacheKey).ConfigureAwait(false); + if (cachedResult != null) + { + logger.LogDebug("[{Caller}] Кэш попал для шаблона {TemplateId}", callerName, template.Id); + return cachedResult.Data.Result; + } + logger.LogDebug("[{Caller}] Начата подстановка шорткодов. Вход: '{Input}', templateId={TemplateId}", callerName, str, template.Id); var result = str; @@ -140,19 +153,29 @@ namespace PARR.DAL.DomainServices.Shortcodes var shortcodes = GetShortCodes(result).Select(m => m.Value).ToList(); if (!shortcodes.Any()) break; - // Подготавливаем данные с догрузкой при необходимости var data = await PrepareTemplateDataAsync(template, shortcodes, callerName).ConfigureAwait(false); - var oldResult = result; - // Подстановка всех типов шорткодов result = await ApplyAllShortcodesOnceAsync(result, data, shortcodes, callerName).ConfigureAwait(false); - iteration++; if (result == oldResult) break; } + // Сохранение в кэш (только если были изменения) + if (!string.IsNullOrEmpty(result) && result != str) + { + var toCache = new ShortcodesResult + { + Data = new ShortcodesResultDto { Result = result }, + Timestamp = DateTimeOffset.UtcNow, + Source = typeof(ShortcodesService).Name + }; + + await cacheService.SetCachedDataAsync(cacheKey, toCache, TimeSpan.FromMinutes(15)).ConfigureAwait(false); + logger.LogDebug("[{Caller}] Результат сохранён в кэш для ключа '{Key}'", callerName, cacheKey); + } + logger.LogDebug("[{Caller}] Подстановка завершена. Результат: '{Result}'", callerName, result); return result; } @@ -772,11 +795,11 @@ namespace PARR.DAL.DomainServices.Shortcodes //var cacheKey = $"gr_shcd_{jobGroupId:N}_{unitId:N}_{ComputeHash(fullShortcode)}"; var cacheKey = cacheService.GetKey(new[] { "grouped", "shortcode", $"{jobGroupId:N}", $"{unitId:N}" }, new[] { fullShortcode }); - var cachedData = await cacheService.GetCachedDataAsync(cacheKey).ConfigureAwait(false); + var cachedData = await cacheService.GetCachedDataAsync(cacheKey).ConfigureAwait(false); if (cachedData != null) { - logger.LogDebug("[{Caller}] Кэш попал для GroupedShortCode '{Name}': {Value}", caller, fullShortcode, cachedData.Value); - return cachedData.Value; + logger.LogDebug("[{Caller}] Кэш попал для GroupedShortCode '{Name}': {Value}", caller, fullShortcode, cachedData.Data.Value); + return cachedData.Data.Value; } logger.LogDebug("[{Caller}] Кэш промахнут для GroupedShortCode '{Name}'. Запрашиваем из БД.", caller, fullShortcode); @@ -793,14 +816,12 @@ namespace PARR.DAL.DomainServices.Shortcodes // Не кэшируем пустые значения if (!string.IsNullOrEmpty(mostFrequentValue)) { - var toCache = new CachedGroupedShortCode + var toCache = new GroupedShortcode { - Value = mostFrequentValue, + Data = new GroupedShortcodeDto { Value = mostFrequentValue }, Timestamp = DateTimeOffset.UtcNow, - Source = typeof(ShortcodesService).Name, - Version = 1 + Source = typeof(ShortcodesService).Name }; - await cacheService.SetCachedDataAsync(cacheKey, toCache, TimeSpan.FromHours(1)).ConfigureAwait(false); return mostFrequentValue; } diff --git a/PARR.Domain/Cache/Models/GroupedShortсode.cs b/PARR.Domain/Cache/Models/GroupedShortсode.cs new file mode 100644 index 00000000..109b7f2b --- /dev/null +++ b/PARR.Domain/Cache/Models/GroupedShortсode.cs @@ -0,0 +1,21 @@ +using PARR.Domain.Cache.Models.Base; + +namespace PARR.Domain.Cache.Models +{ + /// + /// Модель кэша для шорткодов группированных работ + /// + public class GroupedShortcode : IBaseCache + { + public required GroupedShortcodeDto Data { get; set; } + + public DateTimeOffset Timestamp { get; set; } + + public required string Source { get; set; } + } + + public class GroupedShortcodeDto + { + public required string Value { get; set; } + } +} diff --git a/PARR.Domain/Cache/Models/ShortcodesResult.cs b/PARR.Domain/Cache/Models/ShortcodesResult.cs new file mode 100644 index 00000000..643c8e11 --- /dev/null +++ b/PARR.Domain/Cache/Models/ShortcodesResult.cs @@ -0,0 +1,21 @@ +using PARR.Domain.Cache.Models.Base; + +namespace PARR.Domain.Cache.Models +{ + /// + /// Модель кэша для результата подстановки всех шорткодов в строке + /// + public class ShortcodesResult : IBaseCache + { + public required ShortcodesResultDto Data { get; set; } + + public DateTimeOffset Timestamp { get; set; } + + public required string Source { get; set; } + } + + public class ShortcodesResultDto + { + public required string Result { get; set; } + } +} diff --git a/PARR.TemplateMatcher/Services/Implemetaions/SimpleTemplateSynchronizer.cs b/PARR.TemplateMatcher/Services/Implemetaions/SimpleTemplateSynchronizer.cs index 0a34f0d8..bd59e2c0 100644 --- a/PARR.TemplateMatcher/Services/Implemetaions/SimpleTemplateSynchronizer.cs +++ b/PARR.TemplateMatcher/Services/Implemetaions/SimpleTemplateSynchronizer.cs @@ -476,7 +476,7 @@ internal class SimpleTemplateSynchronizer : ITemplateSynchronizer // Находим все шаблоны со статусом Unused var unusedTemplates = await templateService.Get() .Include(t => t.Unit) - .Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Unused || t.StatusTypeId == TemplateStatusTypeEnum.Error) + .Where(t => t.StatusTypeId == TemplateStatusTypeEnum.Unused) .ToListAsync(); if (!unusedTemplates.Any())