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
+36 -26
View File
@@ -2124,22 +2124,18 @@ namespace MP.Data.Controllers
/// </summary>
/// <param name="IdxMacchina"></param>
/// <returns></returns>
public List<string> ParametriGetFilt(string IdxMacchina)
public async Task<List<string>> ParametriGetFiltAsync(string IdxMacchina)
{
List<string> dbResult = new List<string>();
using (var dbCtx = new MoonPro_FluxContext(_configuration))
{
dbResult = dbCtx
.DbSetFluxLog
.AsNoTracking()
.Where(x => (IdxMacchina == "*" || x.IdxMacchina == IdxMacchina))
.Take(1000)
.Select(i => i.CodFlux)
.Distinct()
.OrderBy(x => x)
.ToList();
}
return dbResult;
using var dbCtx = new MoonPro_FluxContext(_configuration);
return await dbCtx
.DbSetFluxLog
.AsNoTracking()
.Where(x => (IdxMacchina == "*" || x.IdxMacchina == IdxMacchina))
.Take(1000)
.Select(i => i.CodFlux)
.Distinct()
.OrderBy(x => x)
.ToListAsync();
}
/// <summary>
@@ -2205,6 +2201,24 @@ namespace MP.Data.Controllers
.FirstOrDefaultAsync() ?? new();
}
/// <summary>
/// Dizionario associazione ODL/PODL
/// </summary>
/// <param name="missingIds"></param>
/// <returns></returns>
public async Task<Dictionary<int, int>> PODL_getDictOdlPodl(List<int> missingIds)
{
if (missingIds == null || !missingIds.Any())
return new Dictionary<int, int>();
using var dbCtx = new MoonProContext(options);
return await dbCtx
.DbSetPODL
.AsNoTracking()
.Where(x => missingIds.Contains(x.IdxOdl))
.ToDictionaryAsync(x => x.IdxOdl, x => x.IdxPromessa);
}
/// <summary>
/// Avvio setup ODL da PODL
/// </summary>
@@ -2451,18 +2465,14 @@ namespace MP.Data.Controllers
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public StatoMacchineModel StatoMacchina(string idxMacchina)
public async Task<StatoMacchineModel> StatoMacchinaAsync(string idxMacchina)
{
StatoMacchineModel dbResult = new StatoMacchineModel();
using (var dbCtx = new MoonProContext(options))
{
dbResult = dbCtx
.DbSetStatoMacc
.Where(x => x.IdxMacchina == idxMacchina)
.AsNoTracking()
.FirstOrDefault();
}
return dbResult;
using var dbCtx = new MoonProContext(options);
return await dbCtx
.DbSetStatoMacc
.Where(x => x.IdxMacchina == idxMacchina)
.AsNoTracking()
.FirstOrDefaultAsync();
}
/// <summary>
+1 -1
View File
@@ -3417,7 +3417,7 @@ namespace MP.Data.Services
result = new StatoMacchineModel();
}
sw.Stop();
Log.Debug($"StatoMacchina | {source} | {sw.Elapsed.TotalMilliseconds}ms");
Log.Debug($"StatoMacchinaAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
+12 -12
View File
@@ -5,13 +5,13 @@
<div class=" rounded small d-flex justify-content-between" title="Filtri attivi">
@*<i class="fas fa-exclamation text-warning"></i>*@
@if (selMacchina != "*")
{
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="()=>resetMacchina()" title="Rimuovi Filtro Impianto"><i class="fa-solid fa-hard-drive"></i> &nbsp <i class="fa-solid fa-xmark text-warning"></i></button>
}
@if (selArticolo != "*")
{
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="()=>resetArticolo()" title="Rimuovi Filtro Articolo"><i class="fa-solid fa-sliders"></i> &nbsp <i class="fa-solid fa-xmark text-warning"></i></button>
}
{
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => resetMacchina()" title="Rimuovi Filtro Impianto"><i class="fa-solid fa-hard-drive"></i> &nbsp <i class="fa-solid fa-xmark text-warning"></i></button>
}
@if (selArticolo != "*")
{
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => resetArticolo()" title="Rimuovi Filtro Articolo"><i class="fa-solid fa-sliders"></i> &nbsp <i class="fa-solid fa-xmark text-warning"></i></button>
}
</div>
}
<div class="p-2">
@@ -34,7 +34,7 @@
</div>
<div class="input-group px-2">
<label class="input-group-text" for="macchina" title="Selezionare l'articolo"><i class="fa-solid fa-file"></i></label>
<select @bind="@selArticolo" class="form-select" id="macchina" title="Selezionare la macchina">
<select @bind="@selArticolo" @bind:after="ReportChangeAsync" class="form-select" id="macchina" title="Selezionare la macchina">
<option value="*">--- Tutti ---</option>
@if (ListArticoli != null)
{
@@ -50,7 +50,7 @@
</div>
<div class="input-group px-2">
<label class="input-group-text" for="macchina" title="Selezionare la macchina"><i class="fa-solid fa-hard-drive"></i></label>
<select @bind="@selMacchina" class="form-select" id="macchina" title="Selezionare la macchina">
<select @bind="@selMacchina" @bind:after="ReportChangeAsync" class="form-select" id="macchina" title="Selezionare la macchina">
<option value="*">--- Tutti ---</option>
@if (ListMacchine != null)
{
@@ -67,14 +67,14 @@
</div>
<div class="px-2 input-group">
<label class="input-group-text" for="dtMin" title="Selezionare inizio periodo"><i class="fa-regular fa-calendar-minus"></i></label>
<input class="form-control" @bind="@selDtMin" id="dtMin" type="datetime-local" title="Data minima eventi da visualizzare">
<input class="form-control" @bind="@selDtMin" @bind:after="ReportChangeAsync" id="dtMin" type="datetime-local" title="Data minima eventi da visualizzare">
</div>
<div class="small mt-2">
<label class="px-2" for="dtMax" title="Selezionare fine periodo">Fine Periodo</label>
</div>
<div class="px-2 input-group">
<label class="input-group-text" for="dtMax" title="Selezionare fine periodo"><i class="fa-regular fa-calendar-plus"></i></label>
<input class="form-control" @bind="@selDtMax" id="dtMax" type="datetime-local" title="Selezionare fine periodo">
<input class="form-control" @bind="@selDtMax" @bind:after="ReportChangeAsync" id="dtMax" type="datetime-local" title="Selezionare fine periodo">
</div>
<div class="small mt-2">
@@ -82,7 +82,7 @@
</div>
<div class="px-2 input-group">
<label class="input-group-text" for="maxRec" title="Numero Max Record"><i class="fa-solid fa-list-numeric"></i></label>
<input class="form-control" @bind="@selMaxRecord" id="maxRec" type="number" title="Max Record recuperati">
<input class="form-control" @bind="@selMaxRecord" @bind:after="ReportChangeAsync" id="maxRec" type="number" title="Max Record recuperati">
</div>
</div>
</div>
+20 -27
View File
@@ -30,26 +30,11 @@ namespace MP.SPEC.Components
{
if (!SelFilterDossier.CodArticolo.Equals(value))
{
SelFilterDossier.CurrPage = 1;
SelFilterDossier.CodArticolo = value;
StateHasChanged();
Task.Delay(1);
reportChange();
}
}
}
private bool filtActive
{
get => selMacchina != "*" || selArticolo != "*";
}
protected void resetMacchina()
{
selMacchina = "*";
}
protected void resetArticolo()
{
selArticolo = "*";
}
protected DateTime selDtMax
{
get
@@ -62,7 +47,6 @@ namespace MP.SPEC.Components
if (!SelFilterDossier.DtEnd.Equals(value))
{
SelFilterDossier.DtEnd = value;
reportChange();
}
}
}
@@ -79,7 +63,6 @@ namespace MP.SPEC.Components
if (!SelFilterDossier.DtStart.Equals(value))
{
SelFilterDossier.DtStart = value;
reportChange();
}
}
}
@@ -94,11 +77,7 @@ namespace MP.SPEC.Components
{
if (!SelFilterDossier.IdxMacchina.Equals(value))
{
SelFilterDossier.CurrPage = 1;
SelFilterDossier.IdxMacchina = value;
StateHasChanged();
Task.Delay(1);
reportChange();
}
}
}
@@ -115,7 +94,6 @@ namespace MP.SPEC.Components
if (!SelFilterDossier.MaxRecord.Equals(value))
{
SelFilterDossier.MaxRecord = value;
reportChange();
}
}
}
@@ -128,8 +106,6 @@ namespace MP.SPEC.Components
protected override async Task OnInitializedAsync()
{
SelFilterDossier = new SelectDossierParams();
SelFilterDossier.MaxRecord = 1000;
DateTime dtEnd = SelFilterDossier.DtEnd;
DateTime dtStart = dtEnd.Subtract(SelFilterDossier.DtStart).TotalDays < 15 ? SelFilterDossier.DtStart : dtEnd.AddDays(-14);
ListMacchine = await MDService.MacchineWithFluxAsync(dtStart, dtEnd);
@@ -137,6 +113,16 @@ namespace MP.SPEC.Components
await FilterChanged.InvokeAsync(SelFilterDossier);
}
protected void resetArticolo()
{
selArticolo = "*";
}
protected void resetMacchina()
{
selMacchina = "*";
}
protected void toggleParams()
{
showEditPar = !showEditPar;
@@ -147,21 +133,28 @@ namespace MP.SPEC.Components
#region Private Fields
private List<string>? ListArticoli = null;
private List<string>? ListMacchine = null;
#endregion Private Fields
#region Private Properties
private bool filtActive
{
get => selMacchina != "*" || selArticolo != "*";
}
private bool showEditPar { get; set; } = false;
#endregion Private Properties
#region Private Methods
private void reportChange()
private Task ReportChangeAsync()
{
FilterChanged.InvokeAsync(SelFilterDossier);
SelFilterDossier.CurrPage = 1;
return FilterChanged.InvokeAsync(SelFilterDossier);
}
private void toggleShowParams()
+5 -1
View File
@@ -398,6 +398,9 @@ namespace MP.SPEC.Components
_podlLocalCache.Clear();
if (SearchRecords != null)
{
var listIdx = SearchRecords.Select(x => x.IdxOdl).ToList();
_podlLocalCache = await MDService.PODL_getDictOdlPodl(listIdx);
#if false
// 1. Popolo la cache locale in parallelo sfruttando la velocità di FusionCache
var tasks = SearchRecords.Select(async odl =>
{
@@ -413,7 +416,8 @@ namespace MP.SPEC.Components
var infoSalvate = await Task.WhenAll(tasks);
// 2. Trasformazione dei risultati in un dizionario per l'accesso immediato (O(1)) nell'HTML
_podlLocalCache = infoSalvate.ToDictionary(x => x.IdxOdl, x => x.podl);
_podlLocalCache = infoSalvate.ToDictionary(x => x.IdxOdl, x => x.podl);
#endif
}
}
+2 -2
View File
@@ -109,7 +109,7 @@ namespace MP.SPEC.Components
SelFilter.CurrPage = 1;
SelFilter.IdxMacchina = value;
SelFilter.CodFlux = "*";
ListFlux = MDService.ParametriGetFilt(selMacchina).Result;
ListFlux = MDService.ParametriGetFiltAsync(selMacchina).Result;
StateHasChanged();
Task.Delay(1);
reportChange();
@@ -182,7 +182,7 @@ namespace MP.SPEC.Components
DateTime dtStart = SelFilter.dtMin != null ? (DateTime)SelFilter.dtMin : DateTime.Now.AddMonths(-1);
DateTime dtEnd = SelFilter.dtMax != null ? (DateTime)SelFilter.dtMax : DateTime.Today.AddDays(1);
ListMacchine = await MDService.MacchineWithFluxAsync(dtStart, dtEnd);
ListFlux = await MDService.ParametriGetFilt(selMacchina);
ListFlux = await MDService.ParametriGetFiltAsync(selMacchina);
var configData = await MDService.ConfigGetAllAsync();
var currRec = configData.FirstOrDefault(x => x.Chiave == "numOreAnticipoSnapshot");
+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;
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>MP.SPEC</RootNamespace>
<Version>8.16.2605.2816</Version>
<Version>8.16.2605.2818</Version>
<UserSecretsId>1800a78a-6ff1-40f9-b490-87fb8bfc1394</UserSecretsId>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
+8 -1
View File
@@ -116,7 +116,14 @@
{
foreach (var item in ListTipoArt)
{
<option value="@item.value">@item.label</option>
if (item.value.Equals("KIT"))
{
<option value="@item.value" disabled>@item.label</option>
}
else
{
<option value="@item.value">@item.label</option>
}
}
}
</select>
+15 -10
View File
@@ -6,16 +6,21 @@
<div class="px-0 py-1">
<h3><b>DOSSIERS</b></h3>
</div>
<div class="px-2 flex-fill">
@if (isFiltering)
{
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
<i>filtro x macchina / periodo</i>
}
else
{
<DossiersFilter FilterChanged="updateFilter"></DossiersFilter>
}
<div class="px-2 flex-fill d-flex align-items-center">
<div class="ms-auto d-flex align-items-center">
<div class="me-3">max rec: <b>@currFilter.MaxRecord</b> &rarr;</div>
<div class="flex-grow-1">
@if (isFiltering)
{
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
<i>filtro x macchina / periodo</i>
}
else
{
<DossiersFilter FilterChanged="updateFilter" SelFilterDossier="currFilter"></DossiersFilter>
}
</div>
</div>
</div>
</div>
</div>
+2 -4
View File
@@ -1,9 +1,8 @@
using EgwCoreLib.Razor;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MP.Data.DbModels;
using MP.SPEC.Components;
using MP.SPEC.Data;
using EgwCoreLib.Razor;
namespace MP.SPEC.Pages
{
@@ -43,7 +42,6 @@ namespace MP.SPEC.Pages
isLoading = true;
isFiltering = true;
// fix pagina
await Task.Delay(1);
var modFilter = currFilter;
modFilter.CurrPage = 1;
currFilter = modFilter;
@@ -71,7 +69,7 @@ namespace MP.SPEC.Pages
#region Private Properties
private SelectDossierParams currFilter { get; set; } = new SelectDossierParams();
private SelectDossierParams currFilter = new SelectDossierParams() { MaxRecord = 200, CurrPage = 1 };
private int currPage
{
+2 -2
View File
@@ -136,7 +136,7 @@ namespace MP.SPEC.Pages
foreach (var idxMacc in CurrMachSel)
{
DateTime adesso = DateTime.Now.Floor(TimeSpan.FromSeconds(1));
var rigaStato = MDService.StatoMacchina(idxMacc);
var rigaStato = await MDService.StatoMacchinaAsync(idxMacc);
string valData = $"SPEC | FRep.Fine | {MService.DomainName}\\{MService.UserName}";
// chiamo stored
@@ -175,7 +175,7 @@ namespace MP.SPEC.Pages
// se conferma ciclo x ogni macchina e registro
foreach (var idxMacc in CurrMachSel)
{
var rigaStato = MDService.StatoMacchina(idxMacc);
var rigaStato = await MDService.StatoMacchinaAsync(idxMacc);
// preparo info utente x Value...
string valData = $"SPEC | FRep.Inizio | {MService.DomainName}\\{MService.UserName}";
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo MAPOSPEC </i>
<h4>Versione: 8.16.2605.2816</h4>
<h4>Versione: 8.16.2605.2818</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
8.16.2605.2816
8.16.2605.2818
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>8.16.2605.2816</version>
<version>8.16.2605.2818</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>
+1
View File
@@ -29,6 +29,7 @@
"cacheCheckArtUsato": 2,
"redisShortTimeCache": 10,
"redisLongTimeCache": 600,
"slowLogThresh": 200,
"MpIoBaseUrl": "http://localhost/MP/IO/",
"MpIoNS": "MoonPro:SQL2016DEV:MoonPro",
"BasePathOdlReturn": "\\\\iis01\\W$\\Files\\ODL",
+1
View File
@@ -70,6 +70,7 @@
"cacheCheckArtUsato": "2",
"redisShortTimeCache": 5,
"redisLongTimeCache": 120,
"slowLogThresh": 1,
"MpIoBaseUrl": "http://localhost:20967/",
"MpIoNS": "MoonPro:SQL2016DEV:MoonPro",
"BasePathOdlReturn": "\\\\iis01\\ODL\\ftpdata\\syncfolder",
+54 -130
View File
@@ -3,143 +3,67 @@
## Obiettivo
Migrare la logica di caching manuale (Redis + DB) verso l'utilizzo di `IFusionCache` per implementare un approccio multi-layer (Memory + Redis + DB), standardizzando l'accesso ai dati.
## Analisi dello stato attuale
- **Classe target**: `MP.SPEC\Data\MpDataService.cs`
- **Pattern attuale**: Molti metodi utilizzano manualmente `redisDb.StringGetAsync` e `redisDb.StringSetAsync` con serializzazione JSON manuale.
- **Metodo Standard**: `GetOrFetchAsync<T>(string operationName, string cacheKey, Func<Task<T>> fetchFunc, TimeSpan expiration, params string[] tags)`.
## Strategia di Migrazione
- **Metodo Standard**: `GetOrFetchAsync<T>(string operationName, string cacheKey, Func<Task<T>> fetchFunc, TimeSpan expiration, params string[] tagList)`.
- **Invalidazione**: Utilizzare i tag tramite `FlushCacheByTagsAsync`.
### 1. Identificazione Metodi Target
Andrò a mappare tutti i metodi in `MpDataService.cs` che:
- Utilizzano `redisDb` direttamente per la lettura/scrittura.
- Gestiscono manualmente la serializzazione/deserializzazione con `JsonConvert`.
- Gestiscono manualmente il fallback dal Redis al DB.
## Stato Avanzamento
### 2. Classificazione Metodi
I metodi verranno suddivisi in:
- **Lettura (Cache-aside)**: Metodi che recuperano dati. Questi saranno i candidati principali per `GetOrFetchAsync`.
- **Scrittura/Invalidazione**: Metodi che aggiornano il DB e devono invalidare la cache (es. `AnagGruppiUpsert`, `ArticoliUpdateRecord`). Questi dovranno utilizzare `_cache.RemoveByTagAsync` o `_cache.RemoveAsync`.
### Fase 1: Analisi e Mapping (Completata)
### 3. Piano di Implementazione (Step-by-Step)
### Fase 2: Refactoring Metodi di Lettura (Cache-aside)
#### Fase 1: Analisi e Mapping
- [ ] Identificare ogni occorrenza di `redisDb.StringGet` / `StringGetAsync` in `MpDataService.cs`.
- [ ] Verificare se la chiave di cache utilizzata è gestita tramite `Utils.redis...`.
#### ✅ Completati (Migrati con `GetOrFetchAsync`)
- `ActionGetReq`
- `AnagEventiGeneralAsync`
- `AnagStatiCommAsync`
- `AnagTipoArtLvAsync`
- `ArticleWithDossierAsync`
- `ArticoliGetByTipoAsync`
- `ArticoliGetSearchAsync`
- `ConfigGetAllAsync`
- `DossiersGetLastFiltAsync`
- `ElencoAziendeAsync`
- `ElencoGruppiFaseAsync`
- `ElencoLinkAsync`
- `FluxLogGetLastFiltAsync`
- `FluxLogParetoAsync`
- `OperatoriGetFiltAsync`
- `POdlGetByOdlAsync`
- `POdlListGetFiltAsync`
- `TksScoreAsync`
- `WipKitFiltAsync`
- `MacchineRecipeArchiveAsync`
- `MacchineRecipeConfAsync`
#### Fase 2: Refactoring Metodi di Lettura
- [x] `ActionGetReq` (Completato)
- [x] `TemplateKitFiltAsync`
- [x] `AnagTipoArtLvAsync`
- [x] `ElencoLinkAsync`
- [x] `ConfigGetAllAsync`
- [x] `DossiersGetLastFiltAsync`
- [x] `ElencoGruppiFaseAsync`
- [x] `IstKitFiltAsync`
- [x] `ListGiacenzeAsync`
- [x] `MacchineWithFluxAsync`
- [x] `POdlListGetFiltAsync`
- [x] `TksScoreAsync`
- [x] `WipKitFiltAsync`
- [x] `POdlGetByOdlAsync`
- [x] `FluxLogGetLastFiltAsync`
- [x] `FluxLogParetoAsync`
- [x] `OperatoriGetFiltAsync`
- [x] `MacchineRecipeArchiveAsync`
- [x] `MacchineRecipeConfAsync`
- [ ] `AnagEventiGeneral`
- [ ] `AnagEventiGetByMacch`
- [ ] `AnagKeyValGetAll`
- [ ] `AnagStatiComm`
- [ ] `AnagTipoArtLvAsync`
- [ ] `ArticleWithDossier`
- [ ] `ConfigGetAll`
- [ ] `DbDedupStats`
- [ ] `ElencoRepartiDTO`
- [ ] `ExpiryReloadParamGet`
- [ ] `IobInfo`
- [ ] `ListPODL_ByCodArt`
- [ ] `MacchineGetFilt`
- [ ] `MacchineRecipeArchive`
- [ ] `MacchineRecipeConf`
- [ ] `MachIobConf`
- [ ] `MseGetAll`
- [ ] `OdlByBatch`
- [ ] `OdlGetCurrentAsync`
- [ ] `OdlListGetFilt`
- [ ] `OperatoriGetFilt`
- [ ] `ParametriGetFilt`
- [ ] `POdlGetByKey`
- [ ] `POdlListByKitParent`
- [ ] `ProcFLStats`
- [ ] `StatoMacchina`
- [ ] `TagConfGetKey`
- [ ] `VocabolarioGetAll`
#### ⏳ In corso / Da Migrare
- `AnagEventiGetByMacch`
- `AnagKeyValGetAll`
- `ConfigGetAll` (Sincrono)
- `ConfigTryGet` (Sincrono)
- `ConfigTryGetAsync`
- `DbDedupStats`
- `ElencoRepartiDTO`
- `ExpiryReloadParamGet`
- `IobInfo`
- `ListPODL_ByCodArt`
- `MacchineGetFilt`
- `MachIobConf`
- `MachIobConfVal`
- `MseGetAll`
- `OdlByBatch`
- `OdlGetCurrentAsync`
- `OdlListGetFilt`
- `OperatoriGetFilt` (Sincrono)
- `ParametriGetFilt`
- `POdlGetByKey`
- `POdlListByKitParent`
- `ProcFLStats`
- `StatoMacchina`
- `TagConfGetKey`
- `VocabolarioGetAll`
#### Fase 3: Refactoring Metodi di Scrittura e Invalidazione
- [ ] `AnagGruppiDelete`
- [ ] `AnagGruppiUpsert`
- [ ] `ArticoliDeleteRecord`
- [ ] `ArticoliUpdateRecord`
- [ ] `ConfigResetCache`
- [ ] `DossiersDeleteRecord`
- [ ] `DossiersTakeParamsSnapshotLast`
- [ ] `IstKitDelete`
- [ ] `IstKitInsertByWKS`
- [ ] `IstKitUpsert`
- [ ] `PodlIstKitDelete`
- [ ] `POdlDoSetup`
- [ ] `POdlUpdateRecipe`
- [ ] `POdlUpdateRecord`
- [ ] `RecipeSetByPODL`
- [ ] `TemplateKitDelete`
- [ ] `TemplateKitUpsert` Fase 2: Refactoring Metodi di Lettura
- [x] `ActionGetReq` (Completato)
- [x] `TemplateKitFiltAsync`
- [x] `AnagTipoArtLvAsync`
- [x] `ElencoLinkAsync`
- [x] `ConfigGetAllAsync`
- [x] `DossiersGetLastFiltAsync`
- [x] `ElencoGruppiFaseAsync`
- [x] `IstKitFiltAsync`
- [x] `ListGiacenzeAsync`
- [x] `MacchineWithFluxAsync`
- [x] `POdlListGetFiltAsync`
- [x] `TksScoreAsync`
- [x] `WipKitFiltAsync`
- [x] `POdlGetByOdlAsync`
- [x] `FluxLogGetLastFiltAsync`
- [x] `FluxLogParetoAsync`
- [ ] `AnagEventiGeneral`
- [ ] `AnagEventiGetByMacch`
- [ ] `AnagKeyValGetAll`
- [ ] `AnagStatiComm`
- [ ] `AnagTipoArtLvAsync`
- [ ] `ArticleWithDossier`
- [ ] `ConfigGetAll`
- [ ] `DbDedupStats`
- [ ] `ElencoRepartiDTO`
- [ ] `ExpiryReloadParamGet`
- [ ] `IobInfo`
- [ ] `ListPODL_ByCodArt`
- [ ] `MacchineGetFilt`
- [ ] `MacchineRecipeArchive`
- [ ] `MacchineRecipeConf`
- [ ] `MachIobConf`
- [ ] `MseGetAll`
- [ ] `OdlByBatch`
- [ ] `OdlGetCurrentAsync`
- [ ] `OdlListGetFilt`
- [ ] `OperatoriGetFilt`
- [ ] `ParametriGetFilt`
- [ ] `POdlGetByKey`
- [ ] `POdlListByKitParent`
- [ ] `ProcFLStats`
- [ ] `StatoMacchina`
- [ ] `TagConfGetKey`
- [ ] `VocabolarioGetAll`
#### Fase 3: Refactoring Metodi di Scrittura e Invalidazione
### Fase 3: Refactoring Metodi di Scrittura e Invalidazione
- [ ] `AnagGruppiDelete`
- [ ] `AnagGruppiUpsert`
- [ ] `ArticoliDeleteRecord`