From 0dfa58f144aca6f6e85c506da2aaaa2196b72001 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Tue, 2 May 2023 17:17:49 -0400 Subject: [PATCH] DefaultOptionsProvider: allow overriding LibName (#2453) If a wrapper package is generally in use in a deployment, it may want to override what we set as the library name in `CLIENT SETINFO lib-name `. This allows doing so via the `DefaultOptionsProvider` (intentionally not on `ConfigurationOptions` directly as version isn't either). Note that this does NOT upgrade the test suite to 7.2.0 RC1. I did test and this works, but there are other breaks we need to evaluate - I'll open another PR separately to demonstrate. --- docs/ReleaseNotes.md | 1 + .../Configuration/DefaultOptionsProvider.cs | 6 ++++ .../PublicAPI/PublicAPI.Shipped.txt | 1 + src/StackExchange.Redis/RedisFeatures.cs | 3 +- src/StackExchange.Redis/RedisLiterals.cs | 1 - src/StackExchange.Redis/ServerEndPoint.cs | 12 +++++--- .../DefaultOptionsTests.cs | 29 +++++++++++++++++++ tests/StackExchange.Redis.Tests/TestBase.cs | 2 +- 8 files changed, 48 insertions(+), 7 deletions(-) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index e3bea8649..1051dfee2 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -13,6 +13,7 @@ Current package versions: - Fix [#2449](https://github.com/StackExchange/StackExchange.Redis/issues/2449): Resolve AOT trim warnings in `TryGetAzureRoleInstanceIdNoThrow` ([#2451 by eerhardt](https://github.com/StackExchange/StackExchange.Redis/pull/2451)) - Adds: Support for `HTTP/1.1 200 Connection established` in HTTP Tunnel ([#2448 by flobernd](https://github.com/StackExchange/StackExchange.Redis/pull/2448)) - Adds: Timeout duration to backlog timeout error messages ([#2452 by NickCraver](https://github.com/StackExchange/StackExchange.Redis/pull/2452)) +- Adds: `DefaultOptionsProvider.LibraryName` for specifying lib-name passed to `CLIENT SETINFO` in Redis 7.2+ ([#2453 by NickCraver](https://github.com/StackExchange/StackExchange.Redis/pull/2453)) ## 2.6.104 diff --git a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs index f990d8265..ced64c8be 100644 --- a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs +++ b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs @@ -197,6 +197,12 @@ protected virtual string GetDefaultClientName() => ?? ComputerName ?? "StackExchange.Redis") + "(SE.Redis-v" + LibraryVersion + ")"; + /// + /// Gets the library name to use for CLIENT SETINFO lib-name calls to Redis during handshake. + /// Defaults to "SE.Redis". + /// + public virtual string LibraryName => "SE.Redis"; + /// /// String version of the StackExchange.Redis library, for use in any options. /// diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index 0f5a2880d..ccfb4edb1 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -1788,6 +1788,7 @@ virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.IncludeDetailIn virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.IncludePerformanceCountersInExceptions.get -> bool virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.IsMatch(System.Net.EndPoint! endpoint) -> bool virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.KeepAliveInterval.get -> System.TimeSpan +virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.LibraryName.get -> string! virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Password.get -> string? virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Proxy.get -> StackExchange.Redis.Proxy virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.ReconnectRetryPolicy.get -> StackExchange.Redis.IReconnectRetryPolicy? diff --git a/src/StackExchange.Redis/RedisFeatures.cs b/src/StackExchange.Redis/RedisFeatures.cs index 1a5bd9b98..70c7d4fbc 100644 --- a/src/StackExchange.Redis/RedisFeatures.cs +++ b/src/StackExchange.Redis/RedisFeatures.cs @@ -39,7 +39,8 @@ public readonly struct RedisFeatures v6_0_0 = new Version(6, 0, 0), v6_0_6 = new Version(6, 0, 6), v6_2_0 = new Version(6, 2, 0), - v7_0_0_rc1 = new Version(6, 9, 240); // 7.0 RC1 is version 6.9.240 + v7_0_0_rc1 = new Version(6, 9, 240), // 7.0 RC1 is version 6.9.240 + v7_2_0_rc1 = new Version(7, 1, 240); // 7.2 RC1 is version 7.1.240 private readonly Version version; diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs index e6d1e76c2..e926b6da4 100644 --- a/src/StackExchange.Redis/RedisLiterals.cs +++ b/src/StackExchange.Redis/RedisLiterals.cs @@ -120,7 +120,6 @@ public static readonly RedisValue REWRITE = "REWRITE", RIGHT = "RIGHT", SAVE = "SAVE", - SE_Redis = "SE.Redis", SEGFAULT = "SEGFAULT", SET = "SET", SETINFO = "SETINFO", diff --git a/src/StackExchange.Redis/ServerEndPoint.cs b/src/StackExchange.Redis/ServerEndPoint.cs index 45b62896c..36163578d 100644 --- a/src/StackExchange.Redis/ServerEndPoint.cs +++ b/src/StackExchange.Redis/ServerEndPoint.cs @@ -935,10 +935,14 @@ private async Task HandshakeAsync(PhysicalConnection connection, LogProxy? log) // server version, so we will use this speculatively and hope for the best log?.WriteLine($"{Format.ToString(this)}: Setting client lib/ver"); - msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, - RedisLiterals.SETINFO, RedisLiterals.lib_name, RedisLiterals.SE_Redis); - msg.SetInternalCall(); - await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait(); + var libName = Multiplexer.RawConfig.Defaults.LibraryName; + if (!string.IsNullOrWhiteSpace(libName)) + { + msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, + RedisLiterals.SETINFO, RedisLiterals.lib_name, libName); + msg.SetInternalCall(); + await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait(); + } var version = Utils.GetLibVersion(); if (!string.IsNullOrWhiteSpace(version)) diff --git a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs index 8223a0d21..e59926379 100644 --- a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs +++ b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -158,4 +159,32 @@ public async Task ClientNameExplicitWins() Assert.True(conn.IsConnected); Assert.Equal("FooBar", conn.ClientName); } + + public class TestLibraryNameOptionsProvider : DefaultOptionsProvider + { + public string Id { get; } = Guid.NewGuid().ToString(); + public override string LibraryName => Id; + } + + [Fact] + public async Task LibraryNameOverride() + { + var options = ConfigurationOptions.Parse(GetConfiguration()); + var defaults = new TestLibraryNameOptionsProvider(); + options.AllowAdmin = true; + options.Defaults = defaults; + + using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + // CLIENT SETINFO is in 7.2.0+ + ThrowIfBelowMinVersion(conn, RedisFeatures.v7_2_0_rc1); + + var clients = await GetServer(conn).ClientListAsync(); + foreach (var client in clients) + { + Log("Library name: " + client.LibraryName); + } + + Assert.True(conn.IsConnected); + Assert.True(clients.Any(c => c.LibraryName == defaults.LibraryName), "Did not find client with name: " + defaults.Id); + } } diff --git a/tests/StackExchange.Redis.Tests/TestBase.cs b/tests/StackExchange.Redis.Tests/TestBase.cs index 98ea41550..6738bf490 100644 --- a/tests/StackExchange.Redis.Tests/TestBase.cs +++ b/tests/StackExchange.Redis.Tests/TestBase.cs @@ -315,7 +315,7 @@ internal virtual IInternalConnectionMultiplexer Create( return conn; } - private void ThrowIfBelowMinVersion(IInternalConnectionMultiplexer conn, Version? requiredVersion) + protected void ThrowIfBelowMinVersion(IConnectionMultiplexer conn, Version? requiredVersion) { if (requiredVersion is null) {