From 063018f9ada8637ffeb72e2c798e0b82f22d367c Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Thu, 11 Jun 2026 17:28:11 +0200 Subject: [PATCH] Update gestione flush service --- MP.RIOC/MP.RIOC.csproj | 2 +- MP.RIOC/Services/MetricsDbFlushService.cs | 82 +++++++++++++---------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/MP.RIOC/MP.RIOC.csproj b/MP.RIOC/MP.RIOC.csproj index 9c6f5aa2..6d0cd1f6 100644 --- a/MP.RIOC/MP.RIOC.csproj +++ b/MP.RIOC/MP.RIOC.csproj @@ -5,7 +5,7 @@ enable enable MP.RIOC - 8.16.2606.1112 + 8.16.2606.1114 diff --git a/MP.RIOC/Services/MetricsDbFlushService.cs b/MP.RIOC/Services/MetricsDbFlushService.cs index 389626c0..10252886 100644 --- a/MP.RIOC/Services/MetricsDbFlushService.cs +++ b/MP.RIOC/Services/MetricsDbFlushService.cs @@ -112,10 +112,9 @@ namespace MP.RIOC.Services var sKey = (RedisKey)$"{statKey}"; if (!TryParseKeyMetadata(sKey, out var meta) || meta.IsHourType) continue; - //// Verifica se la chiave è "orfana" (nessun TTL o TTL troppo lungo >30gg) - //var keyTtl = await _db.KeyTtlAsync(sKey); - //bool isOrphanKey = keyTtl?.TotalSeconds < 0 || keyTtl?.TotalSeconds > 30.25 * 24 * 3600; - bool isOrphanKey = false; + // Verifica se la chiave è "orfana" (nessun TTL o TTL troppo lungo >30gg) + var keyTtl = GetKeyTtl(sKey); + bool isOrphanKey = keyTtl?.TotalSeconds < 0 || keyTtl?.TotalSeconds > 30.25 * 24 * 3600; // Se era scaduta o orfana e abbiamo il permesso, segnamola per la cancellazione if ((meta.Timestamp < currentDayStart || isOrphanKey) && deleteConfirmed) @@ -192,7 +191,7 @@ namespace MP.RIOC.Services int deletedCount = 0; foreach (var key in keysToDelete) { - batch.KeyDeleteAsync(key); + await batch.KeyDeleteAsync(key); deletedCount++; } batch.Execute(); @@ -201,43 +200,56 @@ namespace MP.RIOC.Services } /// - /// Cancellazione ricorsiva chiavi ausiliarie quando si rimuove una chiave principale - /// Rimuove :status, :errors dal sorted set e cancella le chiavi hash ausiliarie + /// Recupera il TTL residuo di una chiave Redis (-1 = nessun TTL, -2 = chiave non esiste) /// - private async Task DeleteAuxKeysAndIndexAsync(RedisKey sKey, string indexKey, IBatch batch) + private TimeSpan? GetKeyTtl(RedisKey key) + { + try + { + return _db.KeyTimeToLive(key); + } + catch { return null; } + } + + /// + /// Cancellazione ricorsiva chiavi ausiliarie (:status, :errors) e rimozione dall'indice + /// + private async Task DeleteAuxKeysAndIndexAsync(RedisKey sKey, RedisKey indexKey, IBatch batch) { string sKeyStr = sKey.ToString(); - string keyDir = sKeyStr.Substring(0, sKeyStr.LastIndexOf(':')); // es: MP_IOC:stats:hour:dest:method:2024061012 + string keyDir = sKeyStr.Substring(0, sKeyStr.LastIndexOf(':')); - // Cancella la chiave ausiliaria :status se presente + // Cancella :status dal sorted set e dalla hash string statusKey = keyDir + ":status"; - RedisValue[] statusMembers = await _db.SortedSetRangeByRankAsync(indexKey, 0, -1); - //if (statusMembers.Any(m => m.ToString() == statusKey)) - //{ - // await batch.SortedSetRemoveAsync(indexKey, statusKey); - // await batch.KeyDeleteAsync(statusKey); - //} + await batch.SortedSetRemoveAsync(indexKey, statusKey); + await batch.KeyDeleteAsync(statusKey); - //// Cancella la chiave ausiliaria :errors se presente - //string errorKey = keyDir + ":errors"; - //if (statusMembers.Any(m => m.ToString() == errorKey)) - //{ - // await batch.SortedSetRemoveAsync(indexKey, errorKey); - // await batch.KeyDeleteAsync(errorKey); - //} + // Cancella :errors dal sorted set e dalla hash + string errorKey = keyDir + ":errors"; + await batch.SortedSetRemoveAsync(indexKey, errorKey); + await batch.KeyDeleteAsync(errorKey); - //// Cancella anche dall'indice days se presente (per chiavi daily) - //if (!sKeyStr.Contains(":hour:")) - //{ - // string daysIndex = keyDir.Replace(":stats:day:", ":stats:days:") - // .Remove(keyDir.Substring(keyDir.IndexOf(":stats:day:") + 12)); - // try - // { - // var dayIndexFull = $"{_redisBaseKey}:stats:days:{keyDir.Split(':')[3]}:{keyDir.Split(':')[4]}"; - // batch.SortedSetRemoveAsync(dayIndexFull, sKey); - // } - // catch { } - //} + // Cancella chiave ausiliaria :status anche da un eventuale indice days se presente + if (statusKey.Contains(":stats:hours:")) + { + string daysIndex = statusKey.Replace(":stats:hours:", ":stats:days:"); + try + { + await batch.SortedSetRemoveAsync(daysIndex, statusKey); + } + catch { } + } + + // Cancella chiave ausiliaria :errors anche da un eventuale indice days se presente + if (errorKey.Contains(":stats:hours:")) + { + string daysIndex = errorKey.Replace(":stats:hours:", ":stats:days:"); + try + { + await batch.SortedSetRemoveAsync(daysIndex, errorKey); + } + catch { } + } } ///