diff --git a/MP.Data/Services/BaseServ.cs b/MP.Data/Services/BaseServ.cs index 0a6dbf7e..df5344c6 100644 --- a/MP.Data/Services/BaseServ.cs +++ b/MP.Data/Services/BaseServ.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; using ZiggyCreatures.Caching.Fusion; -using static Org.BouncyCastle.Asn1.Cmp.Challenge; namespace MP.Data.Services { @@ -54,6 +53,35 @@ namespace MP.Data.Services GC.SuppressFinalize(this); } + /// + /// Cancellazione FusionCache (totale) - wrapper public + /// + /// + public Task ForceFlushFusionCacheAsync() + { + return FlushFusionCacheAsync(); + } + + /// + /// Cancellazione Fusion Cache x tag (wrapper) + /// + /// + /// + public Task ForceFlushFusionCacheAsync(string tag) + { + return FlushFusionCacheAsync(tag); + } + + /// + /// Cancellazione Fusion Cache x list tags (wrapper) + /// + /// + /// + public Task ForceFlushFusionCacheAsync(List listTags) + { + return FlushFusionCacheAsync(listTags); + } + /// /// Recupero info IOB x TAB (da info registrate IOB-WIN--> MP-IO) /// @@ -525,5 +553,50 @@ namespace MP.Data.Services private double slowLogThresh = 0; #endregion Private Fields + + #region Private Methods + + /// + /// Cancellazione FusionCache (totale) + /// + /// + private async Task FlushFusionCacheAsync() + { + await _cache.ClearAsync(allowFailSafe: false); + return true; + } + + /// + /// Cancellazione FusionCache dato singolo tag + /// + /// + /// + private async Task FlushFusionCacheAsync(string tag) + { + if (string.IsNullOrWhiteSpace(tag)) return false; + + await _cache.RemoveByTagAsync(tag); + return true; + } + + /// + /// Cancellazione FusionCache dato elenco tags + /// + /// + /// + private async Task FlushFusionCacheAsync(List listTags) + { + if (listTags == null || listTags.Count == 0) return false; + + // Generiamo i Task di rimozione ed eseguiamoli in parallelo su Redis/L1 + var tasks = listTags + .Where(tag => !string.IsNullOrWhiteSpace(tag)) + .Select(tag => _cache.RemoveByTagAsync(tag).AsTask()); + + await Task.WhenAll(tasks); + return true; + } + + #endregion Private Methods } } \ No newline at end of file diff --git a/MP.Data/Services/IOC/IIocService.cs b/MP.Data/Services/IOC/IIocService.cs index 1eedf50d..5ccfb9f8 100644 --- a/MP.Data/Services/IOC/IIocService.cs +++ b/MP.Data/Services/IOC/IIocService.cs @@ -30,6 +30,20 @@ namespace MP.Data.Services.IOC /// Task ClearFusionCache(); + /// + /// Esegue flush della cache fusion dato tag + /// + /// + /// + Task ClearFusionCache(string tag); + + /// + /// Esegue flush della cache fusion data list tags + /// + /// + /// + Task ClearFusionCache(List listTags); + /// /// Aggiunta record MicroStato + EventList /// diff --git a/MP.Data/Services/IOC/IocService.cs b/MP.Data/Services/IOC/IocService.cs index fbafa6c1..f4901fb0 100644 --- a/MP.Data/Services/IOC/IocService.cs +++ b/MP.Data/Services/IOC/IocService.cs @@ -34,7 +34,7 @@ namespace MP.Data.Services.IOC _repo = repo; _scopeFactory = scopeFactory; #if false - _cache = cache; + _cache = cache; #endif } @@ -58,6 +58,29 @@ namespace MP.Data.Services.IOC return fatto; } + /// + public async Task ClearFusionCache(string tag) + { + if (string.IsNullOrWhiteSpace(tag)) return false; + + await _cache.RemoveByTagAsync(tag); + return true; + } + + /// + public async Task ClearFusionCache(List listTags) + { + if (listTags == null || listTags.Count == 0) return false; + + // Generiamo i Task di rimozione ed eseguiamoli in parallelo su Redis/L1 + var tasks = listTags + .Where(tag => !string.IsNullOrWhiteSpace(tag)) + .Select(tag => _cache.RemoveByTagAsync(tag).AsTask()); + + await Task.WhenAll(tasks); + return true; + } + /// public async Task EvListMicroStatoInsertAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv) { @@ -79,7 +102,7 @@ namespace MP.Data.Services.IOC else { result = await GetCurrOdlByProdAsync(idxMacchina); - _redisDb.StringSet(currKey, result, GetRandTOut(redisLongTimeCache * 2)); + _redisDb.StringSet(currKey, result, GetRandTOut(redisShortTimeCache)); } return result; } @@ -109,7 +132,7 @@ namespace MP.Data.Services.IOC } return val != null && (val == "1" || val.ToLower() == "true"); - }, TimeSpan.FromSeconds(5)); + }, TimeSpan.FromSeconds(5)); #endif bool answ = false; @@ -127,7 +150,6 @@ namespace MP.Data.Services.IOC // provo conversione bool.TryParse($"{rawData}", out answ); return answ; - } /// @@ -179,6 +201,7 @@ namespace MP.Data.Services.IOC // gestisce i casi DB/REDIS secondo necessità await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore, datiMacc); } + await ClearFusionCache(idxMacchina); // forzo RESET dati macchina... await ResetDatiMacchinaAsync(idxMacchina); // registro in risposta che è andato tutto bene... @@ -246,6 +269,7 @@ namespace MP.Data.Services.IOC answ = currCount.ToString(); // salvo per meno tempo... await _redisDb.StringSetAsync(currKey, answ); + await ClearFusionCache(idxMacchina); } } } @@ -277,8 +301,6 @@ namespace MP.Data.Services.IOC #endregion Protected Fields - #region Protected Methods - #if false /// /// Restituisce un timeout dai minuti richiesti + tempo random 1..60 sec @@ -289,17 +311,15 @@ namespace MP.Data.Services.IOC { double rndValue = stdMinutes + (double)rand.Next(1, 60) / 60; return TimeSpan.FromMinutes(rndValue); - } + } #endif - #endregion Protected Methods - #region Private Fields private static Logger Log = LogManager.GetCurrentClassLogger(); #if false - private readonly IFusionCache _cache; + private readonly IFusionCache _cache; #endif private readonly string _className; @@ -317,14 +337,14 @@ namespace MP.Data.Services.IOC /// private string dtFormat = "yyyyMMddHHmmssfff"; + #endregion Private Fields + #if false private int redisLongTimeCache = 5; - private int redisShortTimeCache = 2; + private int redisShortTimeCache = 2; #endif - #endregion Private Fields - #region Private Methods /// @@ -483,7 +503,7 @@ namespace MP.Data.Services.IOC } /// - /// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria + /// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria (versione semplificata) /// /// /// @@ -1020,31 +1040,37 @@ namespace MP.Data.Services.IOC /// private async Task StatoProdMacchinaAsync(string idxMacchina, DateTime dtReq, bool forceDb = false) { - string cacheKey = $"IOC_StatoProd_{idxMacchina}"; + string cKey = $"IOC_StatoProd_{idxMacchina}"; var stdTTL = TimeSpan.FromSeconds(30); - return await GetOrFetchAsync(cacheKey, async () => - { - StatoProdModel? result = new StatoProdModel(); - // cerco in _redisConn... - string currKey = $"{MP.Data.Utils.redisStatoProd}:{idxMacchina}:{dtReq:HHmm}"; - RedisValue rawData = await _redisDb.StringGetAsync(currKey); - if (rawData.HasValue && !forceDb) + return await GetOrFetchAsync( + operationName: "StatoProdMacchinaAsync", + cacheKey: cKey, + fetchFunc: async () => { - result = JsonConvert.DeserializeObject($"{rawData}"); - } - else - { - result = await _repo.StatoProdMacchinaAsync(idxMacchina, dtReq); - // serializzo e salvo... - rawData = JsonConvert.SerializeObject(result); - await _redisDb.StringSetAsync(currKey, rawData, stdTTL); - } - if (result == null) - { - result = new StatoProdModel(); - } - return result; - }, stdTTL); + StatoProdModel? result = new StatoProdModel(); + // cerco in _redisConn... + string currKey = $"{MP.Data.Utils.redisStatoProd}:{idxMacchina}:{dtReq:HHmm}"; + RedisValue rawData = await _redisDb.StringGetAsync(currKey); + if (rawData.HasValue && !forceDb) + { + result = JsonConvert.DeserializeObject($"{rawData}"); + } + else + { + result = await _repo.StatoProdMacchinaAsync(idxMacchina, dtReq); + // serializzo e salvo... + rawData = JsonConvert.SerializeObject(result); + await _redisDb.StringSetAsync(currKey, rawData, stdTTL); + } + if (result == null) + { + result = new StatoProdModel(); + } + return result; + }, + expiration: stdTTL, + tagList: ["IOC_StatoProd", cKey, idxMacchina] + ); } /// diff --git a/MP.IOC/Controllers/IOBController.cs b/MP.IOC/Controllers/IOBController.cs index aecb4945..834d64bd 100644 --- a/MP.IOC/Controllers/IOBController.cs +++ b/MP.IOC/Controllers/IOBController.cs @@ -1086,6 +1086,7 @@ namespace MP.IOC.Controllers try { answ = await DService.saveCaricoPezzi(id, qty); + await IOCService.ClearFusionCache(); return Ok(answ); } catch (Exception exc)