Riorganizzazione codice MpDataService

This commit is contained in:
Samuele Locatelli
2026-05-27 14:11:31 +02:00
parent 13d42d9565
commit 38b8f37d30
+140 -143
View File
@@ -82,18 +82,14 @@ namespace MP.SPEC.Data
#endregion Public Events
#region Public Properties
public static MpSpecController dbController { get; set; } = null!;
public static MpMongoController mongoController { get; set; } = null!;
public MessagePipe BroadastMsgPipe { get; set; } = null!;
public Dictionary<string, List<TagData>> currTagConf { get; set; } = new Dictionary<string, List<TagData>>();
// Cache per controllo eliminazione articoli (Smart HashSet approach)
private HashSet<string> _usedArtIdsCache = new();
private HashSet<string> _unusedArtIdsCache = new();
private DateTime _artCacheExpiry = DateTime.MinValue;
#endregion Public Properties
#region Public Methods
/// <summary>
@@ -412,7 +408,6 @@ namespace MP.SPEC.Data
await dbController.ArticoliGetByTipoAsync(tipo, azienda)
?? new List<AnagArticoliModel>()
);
}
/// <summary>
@@ -438,97 +433,6 @@ namespace MP.SPEC.Data
);
}
/// <summary>
/// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria + tracking attività
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cacheKey"></param>
/// <param name="fetchFunc"></param>
/// <param name="expiration"></param>
/// <returns></returns>
private async Task<T> GetOrFetchAsync<T>(string operationName, string cacheKey, Func<Task<T>> fetchFunc, TimeSpan expiration, params string[] tags)
{
using var activity = ActivitySource.StartActivity(operationName);
string source;
var tryGet = await _cache.TryGetAsync<T>(cacheKey);
if (tryGet.HasValue)
{
source = "MEMORY";
var result = tryGet.Value!;
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
return result;
}
bool fromDb = false;
var final = await _cache.GetOrSetAsync<T>(
cacheKey,
async _ =>
{
fromDb = true;
return await fetchFunc();
},
opt =>
{
opt.SetDuration(expiration)
.SetFailSafe(true);
//if (tags != null && tags.Length > 0)
// opt.SetTags(tags);
});
source = fromDb ? "DB" : "REDIS";
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
return final!;
}
/// <summary>
/// Cancellazione FusionCache (totale)
/// </summary>
/// <returns></returns>
public async Task<bool> FlushCacheAsync()
{
bool fatto = false;
await _cache.ClearAsync();
_configData.Clear();
fatto = true;
return fatto;
}
/// <summary>
/// Cancellazione FusionCache dato elenco tags
/// </summary>
/// <returns></returns>
public async Task<bool> FlushCacheByTagsAsync(List<string> listTags)
{
bool fatto = false;
foreach (var item in listTags)
{
await _cache.RemoveByTagAsync(item);
}
_configData.Clear();
fatto = true;
return fatto;
}
/// <summary>
/// Cancellazione FusionCache dato singolo tag
/// </summary>
/// <returns></returns>
public async Task<bool> FlushCacheByTagAsync(string tag)
{
bool fatto = false;
await _cache.RemoveByTagAsync(tag);
_configData.Clear();
fatto = true;
return fatto;
}
/// <summary>
/// Aggiornamento record selezionato
/// </summary>
@@ -546,7 +450,6 @@ namespace MP.SPEC.Data
return fatto;
}
/// <summary>
/// Verifica se sia possiubile cancellare articolo dato suo CodArt cercando su redis o su
/// tab veto da DB
@@ -592,42 +495,6 @@ namespace MP.SPEC.Data
return !usato;
}
/// <summary>
/// Caricamento asincrono della cache degli articoli (Used/Unused)
/// </summary>
public async Task EnsureArtCacheLoadedAsync(bool forceReload)
{
if (!forceReload && (DateTime.Now < _artCacheExpiry && (_usedArtIdsCache.Count > 0 || _unusedArtIdsCache.Count > 0)))
return;
try
{
// verifico quale sia il set + piccolo
int totalCount = await dbController.ArticoliCountAsync();
int usedCount = await dbController.ArticoliCountUsedAsync();
if (usedCount <= (totalCount - usedCount))
{
var usedList = await dbController.ArticoliGetUsedAsync();
_usedArtIdsCache = new HashSet<string>(usedList.Select(x => x.CodArticolo));
_unusedArtIdsCache.Clear();
}
else
{
var unusedList = await dbController.ArticoliGetUnusedAsync();
_unusedArtIdsCache = new HashSet<string>(unusedList.Select(x => x.CodArticolo));
_usedArtIdsCache.Clear();
}
_artCacheExpiry = DateTime.Now.AddMinutes(15); // TTL ragionevole per la cache locale
}
catch (Exception ex)
{
Log.Error($"Errore nel caricamento cache articoli: {ex.Message}");
_artCacheExpiry = DateTime.Now.AddSeconds(1); // Retry breve in caso di errore
}
}
public string CalcRecipe(RecipeModel currRecipe)
{
using var activity = ActivitySource.StartActivity("CalcRecipe");
@@ -1037,6 +904,41 @@ namespace MP.SPEC.Data
return result;
}
/// <summary>
/// Caricamento asincrono della cache degli articoli (Used/Unused)
/// </summary>
public async Task EnsureArtCacheLoadedAsync(bool forceReload)
{
if (!forceReload && (DateTime.Now < _artCacheExpiry && (_usedArtIdsCache.Count > 0 || _unusedArtIdsCache.Count > 0)))
return;
try
{
// verifico quale sia il set + piccolo
int totalCount = await dbController.ArticoliCountAsync();
int usedCount = await dbController.ArticoliCountUsedAsync();
if (usedCount <= (totalCount - usedCount))
{
var usedList = await dbController.ArticoliGetUsedAsync();
_usedArtIdsCache = new HashSet<string>(usedList.Select(x => x.CodArticolo));
_unusedArtIdsCache.Clear();
}
else
{
var unusedList = await dbController.ArticoliGetUnusedAsync();
_unusedArtIdsCache = new HashSet<string>(unusedList.Select(x => x.CodArticolo));
_usedArtIdsCache.Clear();
}
_artCacheExpiry = DateTime.Now.AddMinutes(15); // TTL ragionevole per la cache locale
}
catch (Exception ex)
{
Log.Error($"Errore nel caricamento cache articoli: {ex.Message}");
_artCacheExpiry = DateTime.Now.AddSeconds(1); // Retry breve in caso di errore
}
}
/// <summary>
/// Aggiunta record EventList
/// </summary>
@@ -1189,6 +1091,48 @@ namespace MP.SPEC.Data
return fatto;
}
/// <summary>
/// Cancellazione FusionCache (totale)
/// </summary>
/// <returns></returns>
public async Task<bool> FlushCacheAsync()
{
bool fatto = false;
await _cache.ClearAsync();
_configData.Clear();
fatto = true;
return fatto;
}
/// <summary>
/// Cancellazione FusionCache dato singolo tag
/// </summary>
/// <returns></returns>
public async Task<bool> FlushCacheByTagAsync(string tag)
{
bool fatto = false;
await _cache.RemoveByTagAsync(tag);
_configData.Clear();
fatto = true;
return fatto;
}
/// <summary>
/// Cancellazione FusionCache dato elenco tags
/// </summary>
/// <returns></returns>
public async Task<bool> FlushCacheByTagsAsync(List<string> listTags)
{
bool fatto = false;
foreach (var item in listTags)
{
await _cache.RemoveByTagAsync(item);
}
_configData.Clear();
fatto = true;
return fatto;
}
public async Task<bool> FlushCacheFluxLog()
{
using var activity = ActivitySource.StartActivity("FlushCacheFluxLog");
@@ -1739,7 +1683,7 @@ namespace MP.SPEC.Data
LogTrace($"MacchineGetFilt | Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
return result;
}
private readonly IFusionCache _cache;
/// <summary>
/// Elenco di tutte le macchine filtrate x gruppo
/// </summary>
@@ -2072,12 +2016,6 @@ namespace MP.SPEC.Data
return dbResult;
}
/// <summary>
/// ODL correnti (tutti)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<List<string>> OdlGetCurrentAsync()
{
string redisKey = Utils.redisOdlCurrByMac;
@@ -2100,7 +2038,11 @@ namespace MP.SPEC.Data
);
}
/// <summary>
/// ODL correnti (tutti)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
/// <summary>
/// elenco TUTTI gli ODL
/// </summary>
@@ -2528,7 +2470,6 @@ namespace MP.SPEC.Data
endDate
) ?? new List<PODLExpModel>()
);
}
/// <summary>
@@ -3256,8 +3197,17 @@ namespace MP.SPEC.Data
private static Logger Log = LogManager.GetCurrentClassLogger();
private readonly IFusionCache _cache;
private DateTime _artCacheExpiry = DateTime.MinValue;
private Dictionary<string, string> _configData = new();
private HashSet<string> _unusedArtIdsCache = new();
// Cache per controllo eliminazione articoli (Smart HashSet approach)
private HashSet<string> _usedArtIdsCache = new();
private string MpIoNS = "";
/// <summary>
@@ -3326,6 +3276,53 @@ namespace MP.SPEC.Data
}
}
/// <summary>
/// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria + tracking attività
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cacheKey"></param>
/// <param name="fetchFunc"></param>
/// <param name="expiration"></param>
/// <returns></returns>
private async Task<T> GetOrFetchAsync<T>(string operationName, string cacheKey, Func<Task<T>> fetchFunc, TimeSpan expiration, params string[] tags)
{
using var activity = ActivitySource.StartActivity(operationName);
string source;
var tryGet = await _cache.TryGetAsync<T>(cacheKey);
if (tryGet.HasValue)
{
source = "MEMORY";
var result = tryGet.Value!;
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
return result;
}
bool fromDb = false;
var final = await _cache.GetOrSetAsync<T>(
cacheKey,
async _ =>
{
fromDb = true;
return await fetchFunc();
},
opt =>
{
opt.SetDuration(expiration)
.SetFailSafe(true);
//if (tags != null && tags.Length > 0)
// opt.SetTags(tags);
});
source = fromDb ? "DB" : "REDIS";
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
return final!;
}
/// <summary>
/// Helper trace messaggio log (SE abilitato)
/// </summary>