save progress

This commit is contained in:
StellaOps Bot
2026-01-03 11:02:24 +02:00
parent ca578801fd
commit 83c37243e0
446 changed files with 22798 additions and 4031 deletions

View File

@@ -107,15 +107,18 @@ public sealed class ResolutionCacheService : IResolutionCacheService
private readonly ResolutionCacheOptions _options;
private readonly ILogger<ResolutionCacheService> _logger;
private readonly JsonSerializerOptions _jsonOptions;
private readonly IRandomSource _random;
public ResolutionCacheService(
IConnectionMultiplexer redis,
IOptions<ResolutionCacheOptions> options,
ILogger<ResolutionCacheService> logger)
ILogger<ResolutionCacheService> logger,
IRandomSource random)
{
_redis = redis ?? throw new ArgumentNullException(nameof(redis));
_options = options?.Value ?? throw new ArgumentNullException(nameof(options));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_random = random ?? throw new ArgumentNullException(nameof(random));
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
@@ -129,7 +132,7 @@ public sealed class ResolutionCacheService : IResolutionCacheService
try
{
var db = _redis.GetDatabase();
var value = await db.StringGetAsync(cacheKey);
var value = await db.StringGetAsync(cacheKey).WaitAsync(ct).ConfigureAwait(false);
if (value.IsNullOrEmpty)
{
@@ -142,7 +145,7 @@ public sealed class ResolutionCacheService : IResolutionCacheService
// Check for probabilistic early expiry
if (_options.EnableEarlyExpiry && cached is not null)
{
var ttl = await db.KeyTimeToLiveAsync(cacheKey);
var ttl = await db.KeyTimeToLiveAsync(cacheKey).WaitAsync(ct).ConfigureAwait(false);
if (ShouldExpireEarly(ttl))
{
_logger.LogDebug("Early expiry triggered for key {CacheKey}", cacheKey);
@@ -153,6 +156,10 @@ public sealed class ResolutionCacheService : IResolutionCacheService
_logger.LogDebug("Cache hit for key {CacheKey}", cacheKey);
return cached;
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to get cache entry for key {CacheKey}", cacheKey);
@@ -168,9 +175,13 @@ public sealed class ResolutionCacheService : IResolutionCacheService
var db = _redis.GetDatabase();
var value = JsonSerializer.Serialize(result, _jsonOptions);
await db.StringSetAsync(cacheKey, value, ttl);
await db.StringSetAsync(cacheKey, value, ttl).WaitAsync(ct).ConfigureAwait(false);
_logger.LogDebug("Cached resolution for key {CacheKey} with TTL {Ttl}", cacheKey, ttl);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to cache resolution for key {CacheKey}", cacheKey);
@@ -182,17 +193,55 @@ public sealed class ResolutionCacheService : IResolutionCacheService
{
try
{
var server = _redis.GetServer(_redis.GetEndPoints().First());
var db = _redis.GetDatabase();
var keys = server.Keys(pattern: pattern).ToArray();
if (keys.Length > 0)
var endpoints = _redis.GetEndPoints();
if (endpoints.Length == 0)
{
await db.KeyDeleteAsync(keys);
_logger.LogInformation("Invalidated {Count} cache entries matching pattern {Pattern}",
keys.Length, pattern);
_logger.LogWarning("No Redis endpoints available for pattern invalidation");
return;
}
const int batchSize = 500;
long totalDeleted = 0;
foreach (var endpoint in endpoints)
{
ct.ThrowIfCancellationRequested();
var server = _redis.GetServer(endpoint);
if (!server.IsConnected)
{
continue;
}
var buffer = new List<RedisKey>(batchSize);
foreach (var key in server.Keys(pattern: pattern, pageSize: batchSize))
{
ct.ThrowIfCancellationRequested();
buffer.Add(key);
if (buffer.Count >= batchSize)
{
totalDeleted += await db.KeyDeleteAsync(buffer.ToArray()).WaitAsync(ct).ConfigureAwait(false);
buffer.Clear();
}
}
if (buffer.Count > 0)
{
totalDeleted += await db.KeyDeleteAsync(buffer.ToArray()).WaitAsync(ct).ConfigureAwait(false);
}
}
if (totalDeleted > 0)
{
_logger.LogInformation(
"Invalidated {Count} cache entries matching pattern {Pattern}",
totalDeleted,
pattern);
}
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
@@ -271,7 +320,7 @@ public sealed class ResolutionCacheService : IResolutionCacheService
return true;
// Probabilistic early expiry using exponential decay
var random = Random.Shared.NextDouble();
var random = _random.NextDouble();
var threshold = _options.EarlyExpiryFactor * Math.Exp(-remainingTtl.Value.TotalSeconds / 3600);
return random < threshold;