diff --git a/MP.IOC/Services/MetricsDbFlushService.cs b/MP.IOC/Services/MetricsDbFlushService.cs index 3731621f..7a2f402c 100644 --- a/MP.IOC/Services/MetricsDbFlushService.cs +++ b/MP.IOC/Services/MetricsDbFlushService.cs @@ -12,6 +12,7 @@ namespace MP.IOC.Services private readonly RouteStatsManager _stats; private readonly IConfiguration _config; private readonly IDatabase _db; + private readonly IConnectionMultiplexer _mux; private static readonly Logger Log = LogManager.GetCurrentClassLogger(); public MetricsDbFlushService( @@ -23,6 +24,7 @@ namespace MP.IOC.Services _stats = stats; _scopeFactory = scopeFactory; _config = config; + _mux = mux; _db = mux.GetDatabase(); } @@ -79,11 +81,11 @@ namespace MP.IOC.Services // Get all hours index keys by pattern matching on existing indices var dests = await GetAllDestinationsAsync(baseKey); - + foreach (var dest in dests) { var hourIndexKey = $"{baseKey}:stats:hours:{dest}:*"; - + try { var allKeys = await _db.KeysAsync(hourIndexKey, 0, -1); @@ -92,49 +94,49 @@ namespace MP.IOC.Services if (!key.IsNullOrEmpty) { allHourIndexKeys.Add(key.ToString()); - + // Read bucket keys from sorted set index var bucketKeys = await _db.SortedSetRangeByRankAsync(key, 0, -1); - + foreach (var bucketKeyRedis in bucketKeys) { if (bucketKeyRedis.IsNullOrEmpty) continue; - + var bucketStr = bucketKeyRedis.ToString(); var parts = bucketStr.Split(':'); - + if (parts.Length < 7) continue; - + // Parse date from key: {base}:stats:hour:{dest}:{method}:{yyyyMMddHH} var dayHourPart = string.Join(":", parts.Skip(6)); - - if (!DateTime.TryParseExact(dayHourPart, "yyyyMMddHH", + + if (!DateTime.TryParseExact(dayHourPart, "yyyyMMddHH", CultureInfo.InvariantCulture, DateTimeStyles.None, out var hourFromKey)) continue; - + if (hourFromKey > cutoff) continue; - + // Read hash data from bucket var hashData = await _db.HashGetAllAsync(bucketKeyRedis); - + if (hashData.Length == 0) continue; - + var countVal = hashData.FirstOrDefault(f => f.Name.ToString() == "count"); var totalMsVal = hashData.FirstOrDefault(f => f.Name.ToString() == "totalMs"); var maxMsVal = hashData.FirstOrDefault(f => f.Name.ToString() == "maxMs"); var minMsVal = hashData.FirstOrDefault(f => f.Name.ToString() == "minMs"); - + if (countVal.Value.IsNullOrEmpty || totalMsVal.Value.IsNullOrEmpty) continue; - + var count = long.TryParse(countVal.Value.ToString(), out var cp) ? cp : 0; var totalMs = double.TryParse(totalMsVal.Value.ToString(), out var tp) ? tp : 0; var maxMs = double.TryParse(maxMsVal.Value.ToString(), out var mp) ? mp : 0; var minMs = double.TryParse(minMsVal.Value.ToString(), out var mip) ? mip : 0; - + if (count == 0) continue; - + var avgDuration = totalMs / count; - + detailRecordsToInsert.Add(new StatsDetailModel { Destination = dest, @@ -659,6 +661,51 @@ namespace MP.IOC.Services return methods.ToList(); } + /// + /// Recupera tutte le chiavi dati gli indici + /// + /// + /// + /// + public async Task> GetDayIndicesAsync(string baseKey, int limit = 10000) + { + var allDayIndices = new List(); + var pattern = $"{baseKey}:stats:days:*"; // Assicurati che il pattern sia corretto + + // 1. Otteniamo tutti gli endpoint (in caso di cluster o replica, potrebbero essere pių di uno) + var endpoints = _mux.GetEndPoints(); + + foreach (var endpoint in endpoints) + { + // 2. Otteniamo l'oggetto Server per quell'endpoint + var server = _mux.GetServer(endpoint); + + // 3. Usiamo KeysAsync che restituisce un IAsyncEnumerable + // Questo metodo gestisce internamente il comando SCAN e il cursore di Redis! + try + { + // L'iterazione č asincrona e molto efficiente + await foreach (var key in server.KeysAsync(pattern: pattern)) + { + //if (key != null) + //{ + //} + allDayIndices.Add(key); + + // Applichiamo il limite di sicurezza che avevi impostato + if (allDayIndices.Count >= limit) + break; + } + } + catch (RedisException ex) + { + Log.Error(ex, $"Errore durante la scansione sull'endpoint {endpoint}"); + } + } + + return allDayIndices; + } + private async Task> GetExpiredHourKeysAsync(string method, DateTime cutoff) { var keys = new List();