Browse Source

Backport to net8 - Caching: SE.Redis update and fix naming inconsistency (#54413)

* 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)

* nit extra ;
Marc Gravell 2 years ago
parent
commit
d638bba694

+ 1 - 1
eng/Versions.props

@@ -318,7 +318,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>

+ 3 - 0
src/Caching/StackExchangeRedis/src/RedisCache.Log.cs

@@ -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);
     }
 }

+ 16 - 9
src/Caching/StackExchangeRedis/src/RedisCache.cs

@@ -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);

+ 2 - 7
src/Caching/StackExchangeRedis/src/RedisCacheOptions.cs

@@ -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;
     }
 }

+ 2 - 7
src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/RedisOutputCacheOptions.cs

@@ -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;
     }
 }

+ 3 - 0
src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/RedisOutputCacheStore.Log.cs

@@ -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);
 }

+ 15 - 1
src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/src/RedisOutputCacheStore.cs

@@ -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;

+ 2 - 1
src/Middleware/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis/test/RedisConnectionFixture.cs

@@ -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();

+ 1 - 0
src/SignalR/server/StackExchangeRedis/src/RedisHubLifetimeManager.cs

@@ -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;
 

+ 2 - 7
src/SignalR/server/StackExchangeRedis/test/TestConnectionMultiplexer.cs

@@ -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