save progress
This commit is contained in:
@@ -22,6 +22,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
{
|
||||
private readonly ConcelierCacheConnectionFactory _connectionFactory;
|
||||
private readonly ConcelierCacheOptions _options;
|
||||
private readonly ConcelierCacheMetrics? _metrics;
|
||||
private readonly ILogger<ValkeyAdvisoryCacheService>? _logger;
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
@@ -36,10 +37,12 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
public ValkeyAdvisoryCacheService(
|
||||
ConcelierCacheConnectionFactory connectionFactory,
|
||||
IOptions<ConcelierCacheOptions> options,
|
||||
ConcelierCacheMetrics? metrics = null,
|
||||
ILogger<ValkeyAdvisoryCacheService>? logger = null)
|
||||
{
|
||||
_connectionFactory = connectionFactory;
|
||||
_options = options.Value;
|
||||
_metrics = metrics;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -51,6 +54,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return null;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -60,11 +64,13 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
if (cached.HasValue)
|
||||
{
|
||||
await db.StringIncrementAsync(AdvisoryCacheKeys.StatsHits(_options.KeyPrefix)).ConfigureAwait(false);
|
||||
_metrics?.RecordHit();
|
||||
_logger?.LogDebug("Cache hit for advisory {MergeHash}", mergeHash);
|
||||
return JsonSerializer.Deserialize<CanonicalAdvisory>((string)cached!, JsonOptions);
|
||||
}
|
||||
|
||||
await db.StringIncrementAsync(AdvisoryCacheKeys.StatsMisses(_options.KeyPrefix)).ConfigureAwait(false);
|
||||
_metrics?.RecordMiss();
|
||||
_logger?.LogDebug("Cache miss for advisory {MergeHash}", mergeHash);
|
||||
return null;
|
||||
}
|
||||
@@ -73,6 +79,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
_logger?.LogWarning(ex, "Failed to get advisory {MergeHash} from cache", mergeHash);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "get");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -83,6 +93,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return [];
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -116,6 +127,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
_logger?.LogWarning(ex, "Failed to get advisories for PURL {Purl}", purl);
|
||||
return [];
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "get-by-purl");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -126,6 +141,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return null;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -144,6 +160,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
_logger?.LogWarning(ex, "Failed to get advisory for CVE {Cve}", cve);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "get-by-cve");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -154,6 +174,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return [];
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -189,6 +210,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
_logger?.LogWarning(ex, "Failed to get hot advisories");
|
||||
return [];
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "get-hot");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -199,6 +224,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -232,6 +258,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
{
|
||||
_logger?.LogWarning(ex, "Failed to cache advisory {MergeHash}", advisory.MergeHash);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "set");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -242,6 +272,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -254,12 +285,17 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
var hotKey = AdvisoryCacheKeys.HotSet(_options.KeyPrefix);
|
||||
await db.SortedSetRemoveAsync(hotKey, mergeHash).ConfigureAwait(false);
|
||||
|
||||
_metrics?.RecordEviction("invalidate");
|
||||
_logger?.LogDebug("Invalidated advisory {MergeHash}", mergeHash);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogWarning(ex, "Failed to invalidate advisory {MergeHash}", mergeHash);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "invalidate");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -270,6 +306,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -283,12 +320,19 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
if (currentSize > _options.MaxHotSetSize)
|
||||
{
|
||||
// Remove lowest scoring entries
|
||||
await db.SortedSetRemoveRangeByRankAsync(
|
||||
var removed = await db.SortedSetRemoveRangeByRankAsync(
|
||||
hotKey,
|
||||
start: 0,
|
||||
stop: currentSize - _options.MaxHotSetSize - 1).ConfigureAwait(false);
|
||||
|
||||
if (removed > 0)
|
||||
{
|
||||
_metrics?.RecordEviction("hotset-trim");
|
||||
}
|
||||
}
|
||||
|
||||
_metrics?.UpdateHotSetSize(Math.Min(currentSize, _options.MaxHotSetSize));
|
||||
|
||||
// Update advisory TTL if cached
|
||||
var advisoryKey = AdvisoryCacheKeys.Advisory(mergeHash, _options.KeyPrefix);
|
||||
if (await db.KeyExistsAsync(advisoryKey).ConfigureAwait(false))
|
||||
@@ -303,6 +347,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
{
|
||||
_logger?.LogWarning(ex, "Failed to update score for {MergeHash}", mergeHash);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "update-score");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -313,6 +361,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -327,6 +376,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
{
|
||||
_logger?.LogWarning(ex, "Failed to index PURL {Purl}", purl);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "index-purl");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -337,6 +390,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -350,6 +404,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
{
|
||||
_logger?.LogWarning(ex, "Failed to unindex PURL {Purl}", purl);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "unindex-purl");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -360,6 +418,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return;
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -373,6 +432,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
{
|
||||
_logger?.LogWarning(ex, "Failed to index CVE {Cve}", cve);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "index-cve");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -424,6 +487,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
{
|
||||
_logger?.LogWarning(ex, "Cache warmup failed after {Elapsed}ms", sw.ElapsedMilliseconds);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "warmup");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -434,6 +501,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return new CacheStatistics { IsHealthy = false };
|
||||
}
|
||||
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
var db = await _connectionFactory.GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
|
||||
@@ -446,6 +514,7 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
var hits = (long)(await db.StringGetAsync(hitsKey).ConfigureAwait(false));
|
||||
var misses = (long)(await db.StringGetAsync(missesKey).ConfigureAwait(false));
|
||||
var hotSetSize = await db.SortedSetLengthAsync(hotKey).ConfigureAwait(false);
|
||||
_metrics?.UpdateHotSetSize(hotSetSize);
|
||||
|
||||
DateTimeOffset? lastWarmup = null;
|
||||
var warmupStr = await db.StringGetAsync(warmupKey).ConfigureAwait(false);
|
||||
@@ -478,6 +547,10 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
_logger?.LogWarning(ex, "Failed to get cache statistics");
|
||||
return new CacheStatistics { IsHealthy = false };
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "stats");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -488,6 +561,30 @@ public sealed class ValkeyAdvisoryCacheService : IAdvisoryCacheService
|
||||
return false;
|
||||
}
|
||||
|
||||
return await _connectionFactory.PingAsync(cancellationToken).ConfigureAwait(false);
|
||||
var sw = StartTiming();
|
||||
try
|
||||
{
|
||||
return await _connectionFactory.PingAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopTiming(sw, "health");
|
||||
}
|
||||
}
|
||||
|
||||
private Stopwatch? StartTiming()
|
||||
{
|
||||
return _metrics is null ? null : Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
private void StopTiming(Stopwatch? sw, string operation)
|
||||
{
|
||||
if (sw is null || _metrics is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
_metrics.RecordLatency(sw.Elapsed.TotalMilliseconds, operation);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user