update parziale DbFlushService
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupera tutte le chiavi dati gli indici
|
||||
/// </summary>
|
||||
/// <param name="baseKey"></param>
|
||||
/// <param name="limit"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<RedisKey>> GetDayIndicesAsync(string baseKey, int limit = 10000)
|
||||
{
|
||||
var allDayIndices = new List<RedisKey>();
|
||||
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<RedisKey>
|
||||
// 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<List<string>> GetExpiredHourKeysAsync(string method, DateTime cutoff)
|
||||
{
|
||||
var keys = new List<string>();
|
||||
|
||||
Reference in New Issue
Block a user