Caching: SE.Redis update and fix naming inconsistency (#54239)

* - rev to SE.Redis 2.7.27
- use new AddLibraryNameSuffix API (2.7.27)
- do not use ConfigurationOptions.Clone() - impacts key rotation
- attach suffix even if ConnectionMultiplexerFactory used (Aspire)
This commit is contained in:
Marc Gravell 2024-02-29 18:30:04 +00:00 коммит произвёл GitHub
Родитель 099bc84939
Коммит 7874b36fd8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 47 добавлений и 33 удалений

Просмотреть файл

@ -324,7 +324,7 @@
<SeleniumWebDriverVersion>4.17.0</SeleniumWebDriverVersion>
<SerilogExtensionsLoggingVersion>1.4.0</SerilogExtensionsLoggingVersion>
<SerilogSinksFileVersion>4.0.0</SerilogSinksFileVersion>
<StackExchangeRedisVersion>2.6.122</StackExchangeRedisVersion>
<StackExchangeRedisVersion>2.7.27</StackExchangeRedisVersion>
<SystemReactiveLinqVersion>5.0.0</SystemReactiveLinqVersion>
<SwashbuckleAspNetCoreVersion>6.4.0</SwashbuckleAspNetCoreVersion>
<XunitAbstractionsVersion>2.0.3</XunitAbstractionsVersion>

Просмотреть файл

@ -12,5 +12,8 @@ public partial class RedisCache
{
[LoggerMessage(1, LogLevel.Warning, "Could not determine the Redis server version. Falling back to use HMSET command instead of HSET.", EventName = "CouldNotDetermineServerVersion")]
public static partial void CouldNotDetermineServerVersion(ILogger logger, Exception exception);
[LoggerMessage(2, LogLevel.Debug, "Unable to add library name suffix.", EventName = "UnableToAddLibraryNameSuffix")]
internal static partial void UnableToAddLibraryNameSuffix(ILogger logger, Exception exception);
}
}

Просмотреть файл

@ -257,14 +257,7 @@ public partial class RedisCache : IDistributedCache, IDisposable
IConnectionMultiplexer connection;
if (_options.ConnectionMultiplexerFactory is null)
{
if (_options.ConfigurationOptions is not null)
{
connection = ConnectionMultiplexer.Connect(_options.ConfigurationOptions);
}
else
{
connection = ConnectionMultiplexer.Connect(_options.Configuration!);
}
connection = ConnectionMultiplexer.Connect(_options.GetConfiguredOptions());
}
else
{
@ -308,7 +301,7 @@ public partial class RedisCache : IDistributedCache, IDisposable
IConnectionMultiplexer connection;
if (_options.ConnectionMultiplexerFactory is null)
{
connection = await ConnectionMultiplexer.ConnectAsync(_options.GetConfiguredOptions("asp.net DC")).ConfigureAwait(false);
connection = await ConnectionMultiplexer.ConnectAsync(_options.GetConfiguredOptions()).ConfigureAwait(false);
}
else
{
@ -332,6 +325,7 @@ public partial class RedisCache : IDistributedCache, IDisposable
WriteTimeTicks(ref _lastConnectTicks, DateTimeOffset.UtcNow);
ValidateServerFeatures(connection);
TryRegisterProfiler(connection);
TryAddSuffix(connection);
}
private void ValidateServerFeatures(IConnectionMultiplexer connection)
@ -369,6 +363,19 @@ public partial class RedisCache : IDistributedCache, IDisposable
}
}
private void TryAddSuffix(IConnectionMultiplexer connection)
{
try
{
connection.AddLibraryNameSuffix("aspnet");
connection.AddLibraryNameSuffix("DC");
}
catch (Exception ex)
{
Log.UnableToAddLibraryNameSuffix(_logger, ex);;
}
}
private byte[]? GetAndRefresh(string key, bool getData)
{
ArgumentNullThrowHelper.ThrowIfNull(key);

Просмотреть файл

@ -59,18 +59,13 @@ public class RedisCacheOptions : IOptions<RedisCacheOptions>
set => _useForceReconnect = value;
}
internal ConfigurationOptions GetConfiguredOptions(string libSuffix)
internal ConfigurationOptions GetConfiguredOptions()
{
var options = ConfigurationOptions?.Clone() ?? ConfigurationOptions.Parse(Configuration!);
var options = ConfigurationOptions ?? ConfigurationOptions.Parse(Configuration!);
// we don't want an initially unavailable server to prevent DI creating the service itself
options.AbortOnConnectFail = false;
if (!string.IsNullOrWhiteSpace(libSuffix))
{
var provider = DefaultOptionsProvider.GetProvider(options.EndPoints);
options.LibraryName = $"{provider.LibraryName} {libSuffix}";
}
return options;
}
}

Просмотреть файл

@ -54,18 +54,13 @@ public sealed class RedisOutputCacheOptions
set => _useForceReconnect = value;
}
internal ConfigurationOptions GetConfiguredOptions(string libSuffix)
internal ConfigurationOptions GetConfiguredOptions()
{
var options = ConfigurationOptions?.Clone() ?? ConfigurationOptions.Parse(Configuration!);
var options = ConfigurationOptions ?? ConfigurationOptions.Parse(Configuration!);
// we don't want an initially unavailable server to prevent DI creating the service itself
options.AbortOnConnectFail = false;
if (!string.IsNullOrWhiteSpace(libSuffix))
{
var provider = DefaultOptionsProvider.GetProvider(options.EndPoints);
options.LibraryName = $"{provider.LibraryName} {libSuffix}";
}
return options;
}
}

Просмотреть файл

@ -14,4 +14,7 @@ internal partial class RedisOutputCacheStore
[LoggerMessage(2, LogLevel.Error, "Fatal error occurred executing redis output-cache GC loop.", EventName = "RedisOutputCacheGCFatalError")]
internal static partial void RedisOutputCacheGCFatalError(ILogger logger, Exception exception);
[LoggerMessage(3, LogLevel.Debug, "Unable to add library name suffix.", EventName = "UnableToAddLibraryNameSuffix")]
internal static partial void UnableToAddLibraryNameSuffix(ILogger logger, Exception exception);
}

Просмотреть файл

@ -332,7 +332,7 @@ internal partial class RedisOutputCacheStore : IOutputCacheStore, IOutputCacheBu
IConnectionMultiplexer connection;
if (_options.ConnectionMultiplexerFactory is null)
{
connection = await ConnectionMultiplexer.ConnectAsync(_options.GetConfiguredOptions("asp.net OC")).ConfigureAwait(false);
connection = await ConnectionMultiplexer.ConnectAsync(_options.GetConfiguredOptions()).ConfigureAwait(false);
}
else
{
@ -415,6 +415,7 @@ internal partial class RedisOutputCacheStore : IOutputCacheStore, IOutputCacheBu
WriteTimeTicks(ref _lastConnectTicks, DateTimeOffset.UtcNow);
ValidateServerFeatures(connection);
TryRegisterProfiler(connection);
TryAddSuffix(connection);
}
private void ValidateServerFeatures(IConnectionMultiplexer connection)
@ -451,6 +452,19 @@ internal partial class RedisOutputCacheStore : IOutputCacheStore, IOutputCacheBu
}
}
private void TryAddSuffix(IConnectionMultiplexer connection)
{
try
{
connection.AddLibraryNameSuffix("aspnet");
connection.AddLibraryNameSuffix("OC");
}
catch (Exception ex)
{
UnableToAddLibraryNameSuffix(_logger, ex);
}
}
private static void WriteTimeTicks(ref long field, DateTimeOffset value)
{
var ticks = value == DateTimeOffset.MinValue ? 0L : value.UtcTicks;

Просмотреть файл

@ -13,8 +13,9 @@ public class RedisConnectionFixture : IDisposable
var options = new RedisOutputCacheOptions
{
Configuration = "127.0.0.1:6379", // TODO: CI test config here
}.GetConfiguredOptions("CI test");
}.GetConfiguredOptions();
_muxer = ConnectionMultiplexer.Connect(options);
_muxer.AddLibraryNameSuffix("test");
}
public IDatabase Database => _muxer.GetDatabase();

Просмотреть файл

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.SignalR.StackExchangeRedis.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using RedisProtocol = Microsoft.AspNetCore.SignalR.StackExchangeRedis.Internal.RedisProtocol; // to disambiguate from StackExchange.Redis.RedisProtocol
namespace Microsoft.AspNetCore.SignalR.StackExchangeRedis;

Просмотреть файл

@ -1,19 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using StackExchange.Redis;
using StackExchange.Redis.Maintenance;
using StackExchange.Redis.Profiling;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Tests;
@ -237,6 +230,8 @@ public class TestConnectionMultiplexer : IConnectionMultiplexer
}
public ValueTask DisposeAsync() => default;
public void AddLibraryNameSuffix(string suffix) { } // don't need to implement
}
public class TestRedisServer