audit, advisories and doctors/setup work

This commit is contained in:
master
2026-01-13 18:53:39 +02:00
parent 9ca7cb183e
commit d7be6ba34b
811 changed files with 54242 additions and 4056 deletions

View File

@@ -18,6 +18,8 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
private readonly JsonSerializerOptions _jsonOptions;
private readonly SemaphoreSlim _connectionLock = new(1, 1);
private IDatabase? _database;
private const int DefaultScanPageSize = 200;
private const int DefaultDeleteBatchSize = 500;
/// <inheritdoc />
public string ProviderName => "valkey";
@@ -43,10 +45,11 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
public async ValueTask<ProvcacheLookupResult> GetAsync(string veriKey, CancellationToken cancellationToken = default)
{
var sw = Stopwatch.StartNew();
cancellationToken.ThrowIfCancellationRequested();
try
{
var db = await GetDatabaseAsync().ConfigureAwait(false);
var db = await GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
var redisKey = BuildKey(veriKey);
var value = await db.StringGetAsync(redisKey).ConfigureAwait(false);
@@ -92,6 +95,7 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
CancellationToken cancellationToken = default)
{
var sw = Stopwatch.StartNew();
cancellationToken.ThrowIfCancellationRequested();
var keyList = veriKeys.ToList();
if (keyList.Count == 0)
@@ -106,7 +110,7 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
try
{
var db = await GetDatabaseAsync().ConfigureAwait(false);
var db = await GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
var redisKeys = keyList.Select(k => (RedisKey)BuildKey(k)).ToArray();
var values = await db.StringGetAsync(redisKeys).ConfigureAwait(false);
@@ -168,7 +172,8 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
{
try
{
var db = await GetDatabaseAsync().ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
var db = await GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
var redisKey = BuildKey(entry.VeriKey);
var value = JsonSerializer.Serialize(entry, _jsonOptions);
@@ -200,18 +205,20 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
public async ValueTask SetManyAsync(IEnumerable<ProvcacheEntry> entries, CancellationToken cancellationToken = default)
{
var entryList = entries.ToList();
cancellationToken.ThrowIfCancellationRequested();
if (entryList.Count == 0)
return;
try
{
var db = await GetDatabaseAsync().ConfigureAwait(false);
var db = await GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
var batch = db.CreateBatch();
var tasks = new List<Task>();
var now = _timeProvider.GetUtcNow();
foreach (var entry in entryList)
{
cancellationToken.ThrowIfCancellationRequested();
var redisKey = BuildKey(entry.VeriKey);
var value = JsonSerializer.Serialize(entry, _jsonOptions);
@@ -242,7 +249,8 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
{
try
{
var db = await GetDatabaseAsync().ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
var db = await GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
var redisKey = BuildKey(veriKey);
var deleted = await db.KeyDeleteAsync(redisKey).ConfigureAwait(false);
@@ -262,16 +270,44 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
{
try
{
var db = await GetDatabaseAsync().ConfigureAwait(false);
var server = _connectionMultiplexer.GetServer(_connectionMultiplexer.GetEndPoints().First());
cancellationToken.ThrowIfCancellationRequested();
var db = await GetDatabaseAsync(cancellationToken).ConfigureAwait(false);
var endpoints = _connectionMultiplexer.GetEndPoints();
if (endpoints.Length == 0)
{
return 0;
}
var fullPattern = $"{_options.ValkeyKeyPrefix}{pattern}";
var keys = server.Keys(pattern: fullPattern).ToArray();
long deleted = 0;
if (keys.Length == 0)
return 0;
foreach (var endpoint in endpoints)
{
cancellationToken.ThrowIfCancellationRequested();
var server = _connectionMultiplexer.GetServer(endpoint);
if (server is null || !server.IsConnected)
{
continue;
}
var deleted = await db.KeyDeleteAsync(keys).ConfigureAwait(false);
var batchKeys = new List<RedisKey>(DefaultDeleteBatchSize);
foreach (var key in server.Keys(pattern: fullPattern, pageSize: DefaultScanPageSize))
{
cancellationToken.ThrowIfCancellationRequested();
batchKeys.Add(key);
if (batchKeys.Count >= DefaultDeleteBatchSize)
{
deleted += await db.KeyDeleteAsync(batchKeys.ToArray()).ConfigureAwait(false);
batchKeys.Clear();
}
}
if (batchKeys.Count > 0)
{
deleted += await db.KeyDeleteAsync(batchKeys.ToArray()).ConfigureAwait(false);
}
}
_logger.LogInformation("Invalidated {Count} cache entries matching pattern {Pattern}", deleted, pattern);
return deleted;
@@ -289,6 +325,7 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
Func<CancellationToken, ValueTask<ProvcacheEntry>> factory,
CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var result = await GetAsync(veriKey, cancellationToken).ConfigureAwait(false);
if (result.IsHit && result.Entry is not null)
{
@@ -303,12 +340,14 @@ public sealed class ValkeyProvcacheStore : IProvcacheStore, IAsyncDisposable
private string BuildKey(string veriKey) => $"{_options.ValkeyKeyPrefix}{veriKey}";
private async Task<IDatabase> GetDatabaseAsync()
private async Task<IDatabase> GetDatabaseAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (_database is not null)
return _database;
await _connectionLock.WaitAsync().ConfigureAwait(false);
await _connectionLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
_database ??= _connectionMultiplexer.GetDatabase();