Update cache con FusionCache in ram

This commit is contained in:
Samuele Locatelli
2026-05-12 07:19:24 +02:00
parent 4c1d8df918
commit 844e19f11f
18 changed files with 109 additions and 43 deletions
+6 -2
View File
@@ -24,10 +24,11 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.36" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.36" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.36" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.1" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.17" />
<PackageVersion Include="MongoDB.Driver" Version="2.19.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="NLog" Version="6.1.3" />
<PackageVersion Include="NLog.Targets.OpenTelemetryProtocol" Version="1.2.6" />
<PackageVersion Include="NLog.Web.AspNetCore" Version="6.1.3" />
@@ -41,7 +42,7 @@
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0" />
<PackageVersion Include="RestSharp" Version="112.0.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="StackExchange.Redis" Version="2.9.17" />
<PackageVersion Include="StackExchange.Redis" Version="2.12.14" />
<PackageVersion Include="System.Data.SqlClient" Version="4.8.6" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.9.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Swagger" Version="6.9.0" />
@@ -49,5 +50,8 @@
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.9.0" />
<PackageVersion Include="YamlDotNet" Version="16.1.0" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.3.0" />
<PackageVersion Include="ZiggyCreatures.FusionCache" Version="2.6.0" />
<PackageVersion Include="ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis" Version="2.6.0" />
<PackageVersion Include="ZiggyCreatures.FusionCache.Serialization.NewtonsoftJson" Version="2.6.0" />
</ItemGroup>
</Project>
+3
View File
@@ -48,6 +48,9 @@
<PackageReference Include="RestSharp" />
<PackageReference Include="SharpZipLib" />
<PackageReference Include="StackExchange.Redis" />
<PackageReference Include="ZiggyCreatures.FusionCache" />
<PackageReference Include="ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis" />
<PackageReference Include="ZiggyCreatures.FusionCache.Serialization.NewtonsoftJson" />
</ItemGroup>
<ItemGroup>
+6
View File
@@ -24,6 +24,12 @@ namespace MP.Data.Services.IOC
/// <returns></returns>
Task<bool> CheckCambiaStatoBatchAsync(tipoInputEvento tipoInput, string IdxMacchina, DateTime InizioStato, int IdxTipo, string CodArt, string Value, int MatrOpr, string pallet);
/// <summary>
/// Esegue clear dell'intera cache fusion in blocco
/// </summary>
/// <returns></returns>
Task<bool> ClearFusionCache();
/// <summary>
/// Aggiunta record MicroStato + EventList
/// </summary>
+29 -21
View File
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MP.Core.Objects;
using MP.Data.DbModels;
@@ -12,6 +11,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using ZiggyCreatures.Caching.Fusion;
using static MP.Core.Objects.Enums;
namespace MP.Data.Services.IOC
@@ -25,7 +25,8 @@ namespace MP.Data.Services.IOC
IConnectionMultiplexer redis,
IIocRepository repo,
IServiceScopeFactory scopeFactory,
Microsoft.Extensions.Caching.Memory.IMemoryCache cache) : base(config, redis)
//Microsoft.Extensions.Caching.Memory.IMemoryCache cache
IFusionCache cache) : base(config, redis)
{
_className = "IocServ";
int.TryParse(config.GetValue<string>("ServerConf:redisLongTimeCache"), out redisLongTimeCache);
@@ -46,6 +47,15 @@ namespace MP.Data.Services.IOC
return success;
}
/// <inheritdoc />
public async Task<bool> ClearFusionCache()
{
bool fatto = false;
await _cache.ClearAsync();
fatto = true;
return fatto;
}
/// <inheritdoc />
public async Task<bool> EvListMicroStatoInsertAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
{
@@ -268,12 +278,12 @@ namespace MP.Data.Services.IOC
private static Logger Log = LogManager.GetCurrentClassLogger();
private readonly Microsoft.Extensions.Caching.Memory.IMemoryCache _cache;
private readonly IFusionCache _cache;
private readonly string _className;
private readonly IIocRepository _repo;
private readonly IServiceScopeFactory _scopeFactory;
private readonly System.Threading.SemaphoreSlim _semaphore = new System.Threading.SemaphoreSlim(1, 1);
/// <summary>
/// Provider CultureInfo x parse valori(es dataora)
@@ -406,8 +416,6 @@ namespace MP.Data.Services.IOC
else
{
result = await _repo.ConfigGetAllAsync();
//result = await Task.FromResult(SpecDbController.ConfigGetAllAsync());
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await _redisDb.StringSetAsync(MP.Data.Utils.redisConfKey, rawData, getRandTOut(redisLongTimeCache));
}
@@ -417,7 +425,7 @@ namespace MP.Data.Services.IOC
result = new List<ConfigModel>();
}
return result;
}, TimeSpan.FromMinutes(10));
}, TimeSpan.FromMinutes(1));
}
/// <summary>
@@ -460,15 +468,15 @@ namespace MP.Data.Services.IOC
/// <returns></returns>
private async Task<T> GetOrFetchAsync<T>(string cacheKey, Func<Task<T>> fetchFunc, TimeSpan expiration)
{
if (_cache.TryGetValue(cacheKey, out T? cachedValue))
{
return cachedValue!;
}
// se non trovato procedo as usual...
T newValue = await fetchFunc();
_cache.Set(cacheKey, newValue, expiration);
return newValue;
// GetOrSetAsync di Fusion cache:
// - TryGetValue, se mancasse crea un lock solo per QUELLA key
// - Esegue fetchFunc (la logica Redis + DB)
// - Salva in memoria e rilascia il lock
return await _cache.GetOrSetAsync<T>(
cacheKey,
async ct => await fetchFunc(),
options => options.SetDuration(expiration)
);
}
/// <summary>
@@ -543,7 +551,7 @@ namespace MP.Data.Services.IOC
await _redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
}
return result;
}, TimeSpan.FromMinutes(5));
}, TimeSpan.FromMinutes(15));
}
private async Task<HashSet<string>> ListSlaveAsync()
@@ -565,7 +573,7 @@ namespace MP.Data.Services.IOC
await _redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
}
return result;
}, TimeSpan.FromMinutes(5));
}, TimeSpan.FromMinutes(15));
}
/// <summary>
@@ -596,7 +604,7 @@ namespace MP.Data.Services.IOC
result = new List<Macchine2SlaveModel>();
}
return result;
}, TimeSpan.FromMinutes(15));
}, TimeSpan.FromMinutes(30));
}
/// <summary>
@@ -1022,7 +1030,7 @@ namespace MP.Data.Services.IOC
result = new StatoProdModel();
}
return result;
}, TimeSpan.FromSeconds(10));
}, TimeSpan.FromSeconds(3));
}
/// <summary>
@@ -41,7 +41,6 @@ namespace MP.Data.Services.Utils
//Task<Dictionary<string, List<StatDataDTO>>> GetParetoStatsDayAsync();
Task<List<StatInfoDto>> GetParetoStatsDayAsync();
/// <summary>
/// Recupera il range di periodi valido per le chiamate di dettaglio.
/// Utilizza la cache automaticamente.
@@ -58,6 +57,12 @@ namespace MP.Data.Services.Utils
/// <returns></returns>
List<ChartSeriesDto> GetTimeSeriesData(List<StatsDetailModel> rawData, bool showCount);
/// <summary>
/// Forza il reset della cache REDIS x i dati
/// </summary>
/// <returns></returns>
Task ResetCache();
/// <summary>
/// Inserisce o aggiorna in batch le statistiche di dettaglio nel database.
/// Opzionalmente elimina i record precedenti nel periodo specificato.
+6 -1
View File
@@ -125,6 +125,12 @@ namespace MP.Data.Services.Utils
return series;
}
/// <inheritdoc />
public async Task ResetCache()
{
await ClearCacheAsync($"{_redisBaseKey}:*");
}
/// <inheritdoc />
public async Task<int> UpsertManyAsync(List<StatsDetailModel> listRecords, bool removeOld)
{
@@ -227,7 +233,6 @@ namespace MP.Data.Services.Utils
return result;
}
#endregion Protected Methods
#region Private Fields
+16 -9
View File
@@ -2,7 +2,14 @@
<div class="card shadow">
<div class="card-header">
<h3>Current Stats</h3>
<div class="d-flex justify-content-between">
<div class="px-0">
<h3>Current Stats</h3>
</div>
<div class="px-0">
<button class="btn btn-primary btn-large" @onclick="() => DoForceReload()">Force Reload</button>
</div>
</div>
</div>
<div class="card-body px-1 py-0">
<div class="row mb-2">
@@ -85,17 +92,17 @@
<div class="input-group">
<span class="input-group-text"># giorni</span>
<input type="number" class="form-control form-control-sm" @bind="numDays" @bind:after="OnDaysChangedAsync">
</div>
</div>
</div>
<div class="card-body">
<MultiLine Id="@currTsId" AspRatio="3" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColorsMLine" backColor="@bgColorsMLine" lTens="0" Titles="@lineTitles" BeginAtZero="@beginAtZero" Stepped="false" Stacked="@lineStacked" ShowLegend="@showLegend" yScale="@scaleFormat"></MultiLine>
</div>
</div>
}
<div class="card-body">
<MultiLine Id="@currTsId" AspRatio="3" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColorsMLine" backColor="@bgColorsMLine" lTens="0" Titles="@lineTitles" BeginAtZero="@beginAtZero" Stepped="false" Stacked="@lineStacked" ShowLegend="@showLegend" yScale="@scaleFormat"></MultiLine>
</div>
</div>
}
</div>
}
</div>
}
</div>
</div>
}
</div>
</div>
@@ -3,6 +3,7 @@ using MP.Core.DTO;
using MP.Data;
using MP.Data.DbModels.Utils;
using MP.Data.DTO;
using MP.Data.Services.IOC;
using MP.Data.Services.Utils;
namespace MP.IOC.Components.Pages
@@ -101,6 +102,9 @@ namespace MP.IOC.Components.Pages
[Inject]
private IStatsDetailService SDetService { get; set; } = null!;
[Inject]
private IIocService IocService { get; set; } = null!;
#endregion Private Properties
#region Private Methods
@@ -110,6 +114,13 @@ namespace MP.IOC.Components.Pages
return currStatSel != null && currStatSel.Title == curKey ? "active" : "";
}
private async Task DoForceReload()
{
await SDetService.ResetCache();
await IocService.ClearFusionCache();
DoReset();
}
private void DoReset()
{
currStatSel = null;
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>8.16.2605.1112</Version>
<Version>8.16.2605.1119</Version>
</PropertyGroup>
<ItemGroup>
+17
View File
@@ -10,6 +10,9 @@ using NLog;
using NLog.Web;
using StackExchange.Redis;
using System.Reflection;
using ZiggyCreatures.Caching.Fusion;
using ZiggyCreatures.Caching.Fusion.Serialization;
using ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson;
var builder = WebApplication.CreateBuilder(args);
@@ -85,6 +88,20 @@ builder.Services.AddSingleton<IConnectionMultiplexer>(redisMux);
//builder.Services.AddScoped<MpDataService>();
builder.Services.AddSingleton<MpDataService>();
// 1. Registra il serializzatore NewtonsoftJson per FusionCache
builder.Services.AddSingleton<IFusionCacheSerializer>(new FusionCacheNewtonsoftJsonSerializer());
// 2. Configura FusionCache solo per la memoria (L1)
builder.Services.AddFusionCache()
.WithDefaultEntryOptions(options =>
{
// Durata di default dei dati in memoria
options.Duration = TimeSpan.FromMinutes(1);
// Jitter: variazione casuale alla scadenza per evitare scadenze in blocco
options.JitterMaxDuration = TimeSpan.FromSeconds(5);
});
logger.Info("Standard service configured");
// WeightProvider: Redis/Memory da config
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo MP-IOC </i>
<h4>Versione: 8.16.2605.1112</h4>
<h4>Versione: 8.16.2605.1119</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
8.16.2605.1112
8.16.2605.1119
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>8.16.2605.1112</version>
<version>8.16.2605.1119</version>
<url>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>MP.RIOC</RootNamespace>
<Version>8.16.2605.1111</Version>
<Version>8.16.2605.1207</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -62,7 +62,7 @@ var httpClientInvoker = new HttpMessageInvoker(new SocketsHttpHandler
UseCookies = false,
// Correzione per il tracing: usa il propagatore corrente di sistema
ActivityHeadersPropagator = DistributedContextPropagator.Current,
ConnectTimeout = TimeSpan.FromSeconds(30),
ConnectTimeout = TimeSpan.FromSeconds(60),
// Gestione certificato (ignora errori per localhost/test)
SslOptions = new System.Net.Security.SslClientAuthenticationOptions
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo MP-RIOC </i>
<h4>Versione: 8.16.2605.1111</h4>
<h4>Versione: 8.16.2605.1207</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
8.16.2605.1111
8.16.2605.1207
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>8.16.2605.1111</version>
<version>8.16.2605.1207</version>
<url>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/MP.RIOC.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>