Ancora updaate caching e gestione oggetti

This commit is contained in:
Samuele Locatelli
2026-05-28 18:49:10 +02:00
parent e0d0f7b493
commit 6b49cb29fe
18 changed files with 281 additions and 268 deletions
+118 -48
View File
@@ -28,6 +28,7 @@ namespace MP.SPEC.Data
_cache = cache;
// Verifica conf trace...
traceEnabled = _configuration.GetValue<bool>("Otel:EnableTracing", false);
slowLogThresh = _configuration.GetValue<double>("ServerConf:slowLogThresh", 1);
Log.Info($"MpDataService | INIT | Trace enabled: {traceEnabled}");
// setup compoenti REDIS
@@ -389,7 +390,10 @@ namespace MP.SPEC.Data
}
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"ArticoloDelEnabled | Cod: {codArticolo} | {source} | {activity?.Duration.TotalMilliseconds}ms");
if (activity?.Duration.TotalMilliseconds > slowLogThresh)
{
LogTrace($"ArticoloDelEnabled | Cod: {codArticolo} | {source} | {activity?.Duration.TotalMilliseconds}ms");
}
return !usato;
}
@@ -480,8 +484,10 @@ namespace MP.SPEC.Data
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"ConfigTryGet Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
if (activity?.Duration.TotalMilliseconds > slowLogThresh)
{
LogTrace($"ConfigTryGet | {keyName} | {source} | {activity?.Duration.TotalMilliseconds}ms");
}
return value ?? "";
}
@@ -501,8 +507,10 @@ namespace MP.SPEC.Data
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"ConfigTryGetAsync | {keyName} | {source} | {activity?.Duration.TotalMilliseconds}ms");
if (activity?.Duration.TotalMilliseconds > slowLogThresh)
{
LogTrace($"ConfigTryGetAsync | {keyName} | {source} | {activity?.Duration.TotalMilliseconds}ms");
}
return value ?? "";
}
@@ -1754,35 +1762,16 @@ namespace MP.SPEC.Data
/// </summary>
/// <param name="IdxMacchina">* = tutte, altrimenti solo x una data idxMaccSel</param>
/// <returns></returns>
public async Task<List<string>> ParametriGetFilt(string IdxMacchina)
public async Task<List<string>> ParametriGetFiltAsync(string IdxMacchina)
{
using var activity = ActivitySource.StartActivity("ParametriGetFilt");
List<string>? result = new List<string>();
string source = "DB";
string currKey = $"{Utils.redisFluxByMac}:{IdxMacchina}";
// cerco in redis dato valore sel idxMaccSel...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
source = "REDIS";
}
else
{
result = await Task.FromResult(dbController.ParametriGetFilt(IdxMacchina));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<string>();
}
activity?.SetTag("data.source", source);
activity?.SetTag("result.count", result.Count);
activity?.Stop();
LogTrace($"ParametriGetFilt | Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
return result;
return await GetOrFetchAsync(
operationName: "ParametriGetFiltAsync",
cacheKey: currKey,
expiration: getRandTOut(redisShortTimeCache),
fetchFunc: async () => await dbController.ParametriGetFiltAsync(IdxMacchina) ?? new(),
tagList: [Utils.redisFluxByMac]
);
}
/// <summary>
@@ -1885,6 +1874,75 @@ namespace MP.SPEC.Data
);
}
/// <summary>
/// Restituisce dizionario ODL/PODL data lista IdxOdl
/// </summary>
/// <param name="idxOdlList"></param>
/// <returns></returns>
public async Task<Dictionary<int, int>> PODL_getDictOdlPodl(List<int> idxOdlList)
{
if (idxOdlList == null || !idxOdlList.Any())
return new Dictionary<int, int>();
var distinctIds = idxOdlList.Distinct().ToList();
var resultDictionary = new Dictionary<int, int>();
var missingIds = new List<int>();
// STEP 1: Controllo rapido in FusionCache (L1/Memory cache)
foreach (var id in distinctIds)
{
var cacheKey = $"val:{id}";
var cachedValue = await _cache.TryGetAsync<int>(cacheKey);
if (cachedValue.HasValue)
{
resultDictionary[id] = cachedValue.Value;
}
else
{
// ID non presente in cache, andrà cercato tramite il servizio EF
missingIds.Add(id);
}
}
// STEP 2: Se ci sono cache miss, interroghiamo il servizio EF Core
if (missingIds.Any())
{
// Riceviamo direttamente un Dictionary<int, int> ottimizzato da EF Core
Dictionary<int, int> dbResults = await dbController.PODL_getDictOdlPodl(missingIds);
// STEP 3: Scriviamo i risultati in cache e li uniamo al dizionario finale
foreach (var kvp in dbResults)
{
var id = kvp.Key;
var targetValue = kvp.Value;
resultDictionary[id] = targetValue;
// Salvataggio atomico e globale su FusionCache
var cacheKey = $"val:{id}";
await _cache.SetAsync(cacheKey, targetValue, TimeSpan.FromMinutes(30));
}
// STEP 4 [Altamente Consigliato]: Cache Penetration Protection
// Se un ID era tra i "missing" ma NON è presente nei risultati del DB, significa che non esiste.
// Salviamo un valore sentinella (es. 0 o -1) per evitare di ricontrollare il DB al prossimo giro.
foreach (var id in missingIds)
{
if (!dbResults.ContainsKey(id))
{
resultDictionary[id] = 0; // Imposta un default per l'output corrente
var cacheKey = $"val:{id}";
await _cache.SetAsync(cacheKey, 0, TimeSpan.FromMinutes(2)); // Scadenza breve per i record inesistenti
}
}
}
return resultDictionary;
}
/// <summary>
/// Effettua il task di eliminazione PODL KIT + istanze + riattivazione PODL originali disattivate tramite stored
/// </summary>
@@ -2200,15 +2258,25 @@ namespace MP.SPEC.Data
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public StatoMacchineModel StatoMacchina(string idxMacchina)
public async Task<StatoMacchineModel> StatoMacchinaAsync(string idxMacchina)
{
using var activity = ActivitySource.StartActivity("StatoMacchina");
string currKey = $"{Utils.redisStatoMacch}:{idxMacchina}";
return await GetOrFetchAsync(
operationName: "StatoMacchinaAsync",
cacheKey: currKey,
expiration: getRandTOut(redisLongTimeCache),
fetchFunc: async () => await dbController.StatoMacchinaAsync(idxMacchina) ?? new(),
tagList: [Utils.redisStatoMacch]
);
#if false
using var activity = ActivitySource.StartActivity("StatoMacchinaAsync");
// setup parametri costanti
string source = "DB";
StatoMacchineModel? result = new StatoMacchineModel();
// cerco in redisConn...
string currKey = $"{Utils.redisStatoMacch}:{idxMacchina}";
RedisValue rawData = redisDb.StringGet(currKey);
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<StatoMacchineModel>($"{rawData}");
@@ -2219,7 +2287,7 @@ namespace MP.SPEC.Data
result = dbController.StatoMacchina(idxMacchina);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(1));
await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(1));
}
if (result == null)
{
@@ -2227,8 +2295,9 @@ namespace MP.SPEC.Data
}
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"StatoMacchina | {source} | {activity?.Duration.TotalMilliseconds}ms");
return result;
LogTrace($"StatoMacchinaAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
return result;
#endif
}
/// <summary>
@@ -2259,23 +2328,15 @@ namespace MP.SPEC.Data
/// <returns></returns>
public async Task<List<TemplateKitModel>> TemplateKitFiltAsync(string codParent, string codChild)
{
using var activity = ActivitySource.StartActivity("TemplateKitFiltAsync");
string source = "DB";
string currKey = $"{Utils.redisKitTempl}:{codParent}:{codChild}";
var result = await GetOrFetchAsync(
return await GetOrFetchAsync(
operationName: "TemplateKitFiltAsync",
cacheKey: currKey,
expiration: getRandTOut(redisLongTimeCache),
fetchFunc: async () => await dbController.TemplateKitFiltAsync(codParent, codChild) ?? new List<TemplateKitModel>(),
tagList: [Utils.redisKitTempl]
);
activity?.SetTag("data.source", source);
activity?.SetTag("result.count", result.Count);
activity?.Stop();
LogTrace($"TemplateKitFiltAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
return result;
}
/// <summary>
@@ -2649,6 +2710,11 @@ namespace MP.SPEC.Data
}
}
/// <summary>
/// Soglia minima (ms) per log timing in console
/// </summary>
private double slowLogThresh = 0;
/// <summary>
/// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria + tracking attività
/// </summary>
@@ -2669,7 +2735,11 @@ namespace MP.SPEC.Data
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
// se supero la soglia loggo...
if (activity?.Duration.TotalMilliseconds > slowLogThresh)
{
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
}
return result;
}
bool fromDb = false;