feat(dal): Результат работы ShortcodesService весь записывается в Redis

This commit is contained in:
Mikhail Kuznetsov
2026-04-21 14:36:24 +10:00
parent 1ed10d5fc6
commit 4cc1269554
5 changed files with 77 additions and 24 deletions

View File

@@ -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;
}
}

View File

@@ -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<ShortcodesResult>(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<CachedGroupedShortCode>(cacheKey).ConfigureAwait(false);
var cachedData = await cacheService.GetCachedDataAsync<GroupedShortcode>(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;
}

View File

@@ -0,0 +1,21 @@
using PARR.Domain.Cache.Models.Base;
namespace PARR.Domain.Cache.Models
{
/// <summary>
/// Модель кэша для шорткодов группированных работ
/// </summary>
public class GroupedShortcode : IBaseCache<GroupedShortcodeDto>
{
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; }
}
}

View File

@@ -0,0 +1,21 @@
using PARR.Domain.Cache.Models.Base;
namespace PARR.Domain.Cache.Models
{
/// <summary>
/// Модель кэша для результата подстановки всех шорткодов в строке
/// </summary>
public class ShortcodesResult : IBaseCache<ShortcodesResultDto>
{
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; }
}
}

View File

@@ -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())