using EgwCoreLib.Lux.Core.Stats;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace EgwCoreLib.Lux.Data.Services
{
///
/// Gestione servizio indice richieste
///
public class CalcRuidService
{
#region Public Constructors
public CalcRuidService(ConnectionMultiplexer redis, TimeSpan retention, string redisBaseKey)
{
_db = redis.GetDatabase();
_retention = retention;
_base = redisBaseKey.TrimEnd(':');
//_base = redisBaseKey.EndsWith(":") ? redisBaseKey : redisBaseKey + ":";
}
#endregion Public Constructors
#region Public Methods
///
/// Metodo Creazione nuova richiesta
///
/// Environment calcolo
/// Tipologia richiesta
/// UID di riferimento
/// restituisce il valore del RUID (ID univoco richiesta)
public async Task AddRequestAsync(string envir, string tipo, string uid)
{
var ruid = GenerateRuid();
var processStart = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
var hashKey = GetRequestKey(ruid);
var setKey = GetSortedSetKey(envir, tipo);
var uidKey = GetUidSetKey(uid);
var combKey = GetCombinationsKey();
var batch = _db.CreateBatch();
// NON await qui!
var t1 = batch.HashSetAsync(hashKey, new HashEntry[]
{
new HashEntry("processStart", processStart),
new HashEntry("UID", uid),
new HashEntry("tipo", tipo),
new HashEntry("envir", envir)
});
var t2 = batch.SortedSetAddAsync(setKey, ruid, processStart);
var t3 = batch.SetAddAsync(uidKey, ruid);
string comb = $"{envir}|{tipo}";
var t4 = batch.SetAddAsync(combKey, comb);
RedisKey minuteKey = Key($"stats:requests:count:{DateTime.UtcNow:yyyyMMddHHmm}");
RedisKey hourKey = Key($"stats:requests:count:{DateTime.UtcNow:yyyyMMddHH}");
var t5 = batch.StringIncrementAsync(minuteKey);
var t6 = batch.StringIncrementAsync(hourKey);
// Esegue il batch
batch.Execute();
// Ora puoi attendere le task
await Task.WhenAll(t1, t2, t3, t4, t5, t6);
return ruid;
}
///
/// Metodo di Cleanup periodico
///
/// Environment calcolo
/// Tipologia richiesta
///
public async Task CleanupOldRequestsAsync(string environment, string tipo)
{
var cutoff = DateTimeOffset.UtcNow.Add(-_retention).ToUnixTimeMilliseconds();
var setKey = GetSortedSetKey(environment, tipo);
var oldIds = await _db.SortedSetRangeByScoreAsync(setKey, stop: cutoff);
if (oldIds.Length == 0) return;
var batch = _db.CreateBatch();
var tasks = new List();
foreach (var id in oldIds)
{
var ruid = id.ToString();
var hashKey = GetRequestKey(ruid);
var uid = await _db.HashGetAsync(hashKey, "UID");
if (!uid.IsNull)
{
var uidKey = GetUidSetKey(uid);
tasks.Add(batch.SetRemoveAsync(uidKey, ruid));
tasks.Add(batch.SetLengthAsync(uidKey).ContinueWith(t =>
{
if (t.Result == 0)
_db.KeyDelete(uidKey);
}));
}
tasks.Add(batch.KeyDeleteAsync(hashKey));
}
tasks.Add(batch.SortedSetRemoveRangeByScoreAsync(setKey, double.NegativeInfinity, cutoff));
tasks.Add(batch.SortedSetLengthAsync(setKey).ContinueWith(t =>
{
if (t.Result == 0)
_db.KeyDelete(setKey);
}));
batch.Execute();
await Task.WhenAll(tasks);
}
///
/// Metodo di Aggiornamento richiesta esistente
///
/// RUID richiesta
///
public async Task CompleteRequestAsync(string ruid)
{
var hashKey = GetRequestKey(ruid);
var processEnd = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
// Recupero processStart
var processStartValue = await _db.HashGetAsync(hashKey, "processStart");
if (processStartValue.IsNull) return;
var processStart = (long)processStartValue;
var elapsed = (processEnd - processStart) / 1000.0; // secondi con decimali
// Recupero max corrente PRIMA del batch
RedisKey hourKeySum = Key($"stats:processing:sum:{DateTime.UtcNow:yyyyMMddHH}");
RedisKey hourKeyMax = Key($"stats:processing:max:{DateTime.UtcNow:yyyyMMddHH}");
var currentMaxValue = await _db.StringGetAsync(hourKeyMax);
double currentMax = currentMaxValue.IsNull ? 0 : (double)currentMaxValue;
var batch = _db.CreateBatch();
// Aggiorno hash
var t1 = batch.HashSetAsync(hashKey, new HashEntry[]
{
new HashEntry("processEnd", processEnd),
new HashEntry("processElapsed", elapsed)
});
// Incremento somma
var t2 = batch.StringIncrementAsync(hourKeySum, elapsed);
// Aggiorno max se necessario
Task t3 = Task.CompletedTask;
if (elapsed > currentMax)
t3 = batch.StringSetAsync(hourKeyMax, elapsed);
// Eseguo batch
batch.Execute();
// Attendo completamento
await Task.WhenAll(t1, t2, t3);
}
///
/// Metodo Recupero combinazioni envir/tipo
///
///
public async Task> GetCombinationsAsync()
{
var members = await _db.SetMembersAsync(GetCombinationsKey());
return members
.Select(x => x.ToString().Split('|'))
.Select(a => (a[0], a[1]));
}
///
/// Metodo Recupero richieste per UID
///
///
///
public async Task> GetRequestsByUidAsync(string uid)
{
var uidKey = GetUidSetKey(uid);
var members = await _db.SetMembersAsync(uidKey);
return members.Select(x => x.ToString());
}
///
/// Metodo Statistiche aggregate
///
///
public async Task