Continuo refactor con cache Fusion

This commit is contained in:
Samuele Locatelli
2026-05-27 09:46:55 +02:00
parent 9e4594f8b4
commit 1eb5185240
10 changed files with 100 additions and 16 deletions
+22 -2
View File
@@ -164,9 +164,9 @@ namespace MP.Data.Controllers
/// Elenco Gruppi tipo Azienda
/// </summary>
/// <returns></returns>
public List<AnagGruppiModel> AnagGruppiAziende()
public Task<List<AnagGruppiModel>> AnagGruppiAziendeAsync()
{
return AnagGruppiGetTipo("AZIENDA");
return AnagGruppiGetTipoAsync("AZIENDA");
}
/// <summary>
@@ -241,6 +241,26 @@ namespace MP.Data.Controllers
return dbResult;
}
/// <summary>
/// Gruppi x tipo modalità Async
/// </summary>
/// <param name="tipoGruppo"></param>
/// <returns></returns>
public async Task<List<AnagGruppiModel>> AnagGruppiGetTipoAsync(string tipoGruppo)
{
List<AnagGruppiModel> dbResult = new List<AnagGruppiModel>();
using (var dbCtx = new MoonProContext(options))
{
dbResult = await dbCtx
.DbSetAnagGruppi
.Where(x => x.TipoGruppo == tipoGruppo)
.AsNoTracking()
.OrderBy(x => x.CodGruppo)
.ToListAsync();
}
return dbResult;
}
/// <summary>
/// Elenco Gruppi tipo REPARTO (x associazione Macchine-Operatori)
/// </summary>
+1 -3
View File
@@ -1,12 +1,9 @@
using Amazon.Runtime.Internal.Endpoints.StandardLibrary;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.JSInterop;
using MP.AppAuth.Services;
using MP.SPEC.Data;
using MP.SPEC.Extensions;
using System;
namespace MP.SPEC.Components
{
@@ -56,6 +53,7 @@ namespace MP.SPEC.Components
protected async Task FlushCache()
{
await MDService.FlushRedisCache();
await MDService.FlushCacheAsync();
await ForceReload();
// rimando a pagina corrente
NavManager.NavigateTo(NavManager.Uri, true);
+8 -5
View File
@@ -306,7 +306,7 @@ namespace MP.SPEC.Data
return await GetOrFetchAsync(
operationName: "AnagStatiCommAsync",
cacheKey: Utils.redisStatoCom,
expiration: TimeSpan.FromMinutes(5),
expiration: TimeSpan.FromMinutes(redisLongTimeCache),
fetchFunc: async () =>
await dbController.AnagStatiCommAsync() ?? new List<ListValuesModel>()
);
@@ -633,6 +633,7 @@ namespace MP.SPEC.Data
{
bool fatto = false;
await _cache.ClearAsync();
_configData.Clear();
fatto = true;
return fatto;
}
@@ -648,6 +649,7 @@ namespace MP.SPEC.Data
{
await _cache.RemoveByTagAsync(item);
}
_configData.Clear();
fatto = true;
return fatto;
}
@@ -659,6 +661,7 @@ namespace MP.SPEC.Data
{
bool fatto = false;
await _cache.RemoveByTagAsync(tag);
_configData.Clear();
fatto = true;
return fatto;
}
@@ -1198,14 +1201,14 @@ namespace MP.SPEC.Data
/// Restitusice elenco aziende
/// </summary>
/// <returns></returns>
public List<AnagGruppiModel> ElencoAziende()
public async Task<List<AnagGruppiModel>> ElencoAziendeAsync()
{
using var activity = ActivitySource.StartActivity("ElencoAziende");
using var activity = ActivitySource.StartActivity("ElencoAziendeAsync");
string source = "DB";
var listAz = dbController.AnagGruppiAziende();
var listAz = await dbController.AnagGruppiAziendeAsync();
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"ElencoAziende | Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
LogTrace($"ElencoAziendeAsync | Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
return listAz;
}
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>MP.SPEC</RootNamespace>
<Version>8.16.2605.2708</Version>
<Version>8.16.2605.2709</Version>
<UserSecretsId>1800a78a-6ff1-40f9-b490-87fb8bfc1394</UserSecretsId>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
+1 -1
View File
@@ -176,7 +176,7 @@ namespace MP.SPEC.Pages
{
selAzienda = "*";
}
ListAziende = MDService.ElencoAziende();
ListAziende = await MDService.ElencoAziendeAsync();
ListTipoArt = await MDService.AnagTipoArtLV();
}
+1 -1
View File
@@ -129,7 +129,7 @@ namespace MP.SPEC.Pages
protected override async Task OnInitializedAsync()
{
await getReparto();
ListAziende = MDService.ElencoAziende();
ListAziende = await MDService.ElencoAziendeAsync();
var allGruppiData = MDService.ElencoGruppiFase();
if (allGruppiData != null)
{
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo MAPOSPEC </i>
<h4>Versione: 8.16.2605.2708</h4>
<h4>Versione: 8.16.2605.2709</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
8.16.2605.2708
8.16.2605.2709
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>8.16.2605.2708</version>
<version>8.16.2605.2709</version>
<url>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/MP.SPEC.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+63
View File
@@ -0,0 +1,63 @@
# Refactoring Plan: MpDataService Cache Layer Upgrade
## Objective
Migrate all data access methods in `MpDataService.cs` to use the unified multi-level cache stack (IMemoryCache via `IFusionCache` + Redis + DB) using the `GetOrFetchAsync` pattern.
## Current State
- Some methods use a manual "Redis + DB" approach (checking `redisDb.StringGet`, deserializing, and then `StringSet` on miss).
- Some methods use the new `GetOrFetchAsync` pattern (Memory + Redis + DB).
- `GetOrFetchAsync` leverages `IFusionCache`, which handles the multi-level complexity and provides better resiliency (fail-safe).
## Target Pattern: `GetOrFetchAsync`
All read methods should be refactored to:
1. Use `GetOrFetchAsync` to abstract cache management.
2. Define a `cacheKey` (typically matching the existing Redis key).
3. Provide an `expiration` (TimeSpan).
4. Provide a `fetchFunc` that calls the `dbController` method.
## Proposed Work Items
### 1. Analysis & Categorization
Identify all methods in `MpDataService.cs` that currently implement manual Redis caching.
**Candidates for Refactoring (Redis + DB -> Multi-level):**
- `AnagEventiGeneral` (Lines 166-195)
- `AnagEventiGetByMacch` (Lines 201-230)
- `AnagKeyValGetAll` (Lines 273-302)
- `AnagTipoArtLV` (Lines 347-375)
- `ArticleWithDossier` (Lines 381-410)
- `ConfigGetAll` (Lines 907-936)
- `ConfigGetAllAsync` (Lines 943-970)
- `DbDedupStats` (Lines 1046-1067)
- `ElencoGruppiFase` (Lines 1216-1249)
- `ElencoRepartiDTO` (Lines 1267-1303)
- `FluxLogGetLastFilt` (Lines 1569-1605)
- `FluxLogPareto` (Lines 1609-1640)
- `MacchineRecipeArchive` (Lines 2100-2128)
- `MacchineRecipeConf` (Lines 2131-2163)
- `MacchineWithFlux` (Lines 2171-2200)
- `OdlByBatch` (Lines 2308-2336)
- `OdlListAll` (Lines 2490-2499) - *Currently no cache, needs addition?*
- `OdlListGetFilt` (Lines 2513-2542)
- `OperatoriGetFilt` (Lines 2549-2577)
- `ParametriGetFilt` (Lines 2585-2614)
- `POdlGetByKey` (Lines 2658-2697)
- `POdlGetByOdl` (Lines 2705-2744)
- `POdlListByKitParent` (Lines 2770-2800)
- `POdlListGetFilt` (Lines 2812-2841)
- `TksScore` (Lines 3343-3372)
- `VocabolarioGetAll` (Lines 3445-3477)
- `WipKitFilt` (Lines 3543-3570)
### 2. Implementation Steps
For each candidate method:
1. **Convert to Async**: If the method is synchronous (e.g., `AnagEventiGeneral`), convert it to `Task<T>` to match the `GetOrFetchAsync` signature.
2. **Map Keys**: Ensure the `cacheKey` passed to `GetOrFetchAsync` is identical to the old Redis key to prevent cache fragmentation.
3. **Set Expiration**: Use appropriate `TimeSpan` (e.g., `redisLongTimeCache` or `redisShortTimeCache` converted to `TimeSpan`).
4. **Cleanup**: Remove manual `JsonConvert` logic and `redisDb.StringGet/Set` calls.
5. **Verify Tracing**: Ensure `ActivitySource` and `LogTrace` are preserved or integrated within the `GetOrFetchAsync` wrapper.
### 3. Validation
- Ensure all refactored methods are still called correctly by consumers.
- Verify that `GetOrFetchAsync` correctly hits Memory first, then Redis, then DB.
- Confirm that `LogTrace` still reports the correct source (MEMORY, REDIS, or DB).