diff --git a/MP.RIOC/Services/MetricsDbFlushService.cs b/MP.RIOC/Services/MetricsDbFlushService.cs index 4d2cbd71..ac1e1ca2 100644 --- a/MP.RIOC/Services/MetricsDbFlushService.cs +++ b/MP.RIOC/Services/MetricsDbFlushService.cs @@ -110,21 +110,23 @@ namespace MP.RIOC.Services foreach (var statKey in memberKeys) { var sKey = (RedisKey)$"{statKey}"; -#if false - if (!TryParseKeyMetadata(sKey, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType)) - continue; -#endif if (!TryParseKeyMetadata(sKey, out var meta) || meta.IsHourType) continue; - // Se fosse scaduta e abbiamo il permesso, segnamola per la cancellazione - if (meta.Timestamp < currentDayStart && deleteConfirmed) + // 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; + + // Se era scaduta o orfana e abbiamo il permesso, segnamola per la cancellazione + if ((meta.Timestamp < currentDayStart || isOrphanKey) && deleteConfirmed) { // 1. Segna la chiave Hash (Dati) per l'eliminazione keysToDelete.Add(sKey); - // 2. CORREZIONE: Devi rimuovere il riferimento dal Sorted Set (Indice) - // Usiamo il batch per essere efficienti - _ = batch.SortedSetRemoveAsync(indexKey, statKey); + // 2. Rimuovi il riferimento dal Sorted Set (Indice) + batch.SortedSetRemoveAsync(indexKey, statKey); + + // 3. Cancellazione ricorsiva delle chiavi ausiliarie (:status, :errors, :days) + await DeleteAuxKeysAndIndexAsync(sKey, indexKey, batch); } // Recupero dati dalla Hash @@ -137,7 +139,6 @@ namespace MP.RIOC.Services dict.TryGetValue("totalMs", out var totalMsStr)) { long count = long.Parse(countStr); - count = long.Parse(countStr); double totalMs = double.Parse(totalMsStr, CultureInfo.InvariantCulture); double maxMs = dict.ContainsKey("maxMs") ? double.Parse(dict["maxMs"], CultureInfo.InvariantCulture) : 0; @@ -190,7 +191,7 @@ namespace MP.RIOC.Services int deletedCount = 0; foreach (var key in keysToDelete) { - _ = batch.KeyDeleteAsync(key); + batch.KeyDeleteAsync(key); deletedCount++; } batch.Execute(); @@ -198,6 +199,46 @@ 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 + /// + private async Task DeleteAuxKeysAndIndexAsync(RedisKey sKey, string indexKey, IBatch batch) + { + string sKeyStr = sKey.ToString(); + string keyDir = sKeyStr.Substring(0, sKeyStr.LastIndexOf(':')); // es: MP_IOC:stats:hour:dest:method:2024061012 + + // Cancella la chiave ausiliaria :status se presente + string statusKey = keyDir + ":status"; + RedisValue[] statusMembers = await _db.SortedSetRangeByRankAsync(indexKey, 0, -1); + if (statusMembers.Any(m => m.ToString() == statusKey)) + { + batch.SortedSetRemoveAsync(indexKey, statusKey); + batch.KeyDeleteAsync(statusKey); + } + + // Cancella la chiave ausiliaria :errors se presente + string errorKey = keyDir + ":errors"; + if (statusMembers.Any(m => m.ToString() == errorKey)) + { + batch.SortedSetRemoveAsync(indexKey, errorKey); + 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 { } + } + } + /// /// Processing dati orari (da Redis a DB) /// @@ -244,26 +285,22 @@ namespace MP.RIOC.Services { var sKey = (RedisKey)$"{statKey}"; if (!TryParseKeyMetadata(sKey, out var meta) || !meta.IsHourType) continue; -#if false - if (!TryParseKeyMetadata(sKey, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType)) - continue; - // Verifica se la chiave fosse scaduta rispetto all'orario corrente - bool isExpired = isHourType - ? timestamp < currentHourStart - : false; - //: timestamp < currentDayStart; -#endif + // Verifica se la chiave è "orfana" (nessun TTL o TTL troppo lungo) + var keyTtl = await _db.KeyTtlAsync(sKey); + bool isOrphanKey = keyTtl?.TotalSeconds < 0 || keyTtl?.TotalSeconds > 30.25 * 24 * 3600; - // Se fosse scaduta e abbiamo il permesso, segnamola per la cancellazione - if (meta.Timestamp < currentHourStart && deleteConfirmed) + // Se era scaduta o orfana e abbiamo il permesso, segnamola per la cancellazione + if ((meta.Timestamp < currentHourStart || isOrphanKey) && deleteConfirmed) { // 1. Segna la chiave Hash (Dati) per l'eliminazione keysToDelete.Add(sKey); - // 2. CORREZIONE: Devi rimuovere il riferimento dal Sorted Set (Indice) - // Usiamo il batch per essere efficienti - _ = batch.SortedSetRemoveAsync(indexKey, statKey); + // 2. Rimuovi il riferimento dal Sorted Set (Indice) + batch.SortedSetRemoveAsync(indexKey, statKey); + + // 3. Cancellazione ricorsiva chiavi ausiliarie + await DeleteAuxKeysAndIndexAsync(sKey, indexKey, batch); } // Recupero dati dalla Hash diff --git a/MP.SPEC/MP.SPEC.csproj b/MP.SPEC/MP.SPEC.csproj index 9a6193ce..e4246aa7 100644 --- a/MP.SPEC/MP.SPEC.csproj +++ b/MP.SPEC/MP.SPEC.csproj @@ -5,7 +5,7 @@ enable enable MP.SPEC - 8.16.2606.1021 + 8.16.2606.1112 1800a78a-6ff1-40f9-b490-87fb8bfc1394 en diff --git a/MP.SPEC/Resources/ChangeLog.html b/MP.SPEC/Resources/ChangeLog.html index 82ce6cd5..827560a5 100644 --- a/MP.SPEC/Resources/ChangeLog.html +++ b/MP.SPEC/Resources/ChangeLog.html @@ -1,6 +1,6 @@ Modulo MAPOSPEC -

Versione: 8.16.2606.1021

+

Versione: 8.16.2606.1112


Note di rilascio: