diff --git a/src/StackExchange.Redis/CommandMap.cs b/src/StackExchange.Redis/CommandMap.cs
index a12828033..b22fd5ae9 100644
--- a/src/StackExchange.Redis/CommandMap.cs
+++ b/src/StackExchange.Redis/CommandMap.cs
@@ -7,7 +7,7 @@ namespace StackExchange.Redis
///
/// Represents the commands mapped on a particular configuration.
///
- public sealed class CommandMap
+ public sealed class CommandMap // TODO: (RESP3) add HELLO command here?
{
private readonly CommandBytes[] map;
diff --git a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
index 72b1d3997..744e48bbf 100644
--- a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
+++ b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
@@ -141,6 +141,11 @@ public static void AddProvider(DefaultOptionsProvider provider)
///
public virtual TimeSpan KeepAliveInterval => TimeSpan.FromSeconds(60);
+ ///
+ /// Which Resp protocol to use (default is RESP 2).
+ ///
+ public virtual string Protocol => "2";
+
///
/// Type of proxy to use (if any); for example .
///
diff --git a/src/StackExchange.Redis/ConfigurationOptions.cs b/src/StackExchange.Redis/ConfigurationOptions.cs
index e773944d1..91702fa0e 100644
--- a/src/StackExchange.Redis/ConfigurationOptions.cs
+++ b/src/StackExchange.Redis/ConfigurationOptions.cs
@@ -85,6 +85,7 @@ internal const string
User = "user",
Password = "password",
PreserveAsyncOrder = "preserveAsyncOrder",
+ Protocol = "protocol",
Proxy = "proxy",
ResolveDns = "resolveDns",
ResponseTimeout = "responseTimeout",
@@ -116,6 +117,7 @@ internal const string
User,
Password,
PreserveAsyncOrder,
+ Protocol,
Proxy,
ResolveDns,
ServiceName,
@@ -144,7 +146,7 @@ public static string TryNormalize(string value)
private bool? allowAdmin, abortOnConnectFail, resolveDns, ssl, checkCertificateRevocation,
includeDetailInExceptions, includePerformanceCountersInExceptions;
- private string? tieBreaker, sslHost, configChannel;
+ private string? tieBreaker, sslHost, configChannel, protocol;
private TimeSpan? heartbeatInterval;
@@ -449,6 +451,15 @@ public bool PreserveAsyncOrder
set { }
}
+ ///
+ /// Which Resp protocol to use (default is RESP 2).
+ ///
+ public string Protocol
+ {
+ get => protocol ?? Defaults.Protocol;
+ set => protocol = value;
+ }
+
///
/// Type of proxy to use (if any); for example .
///
@@ -632,6 +643,7 @@ public static ConfigurationOptions Parse(string configuration, bool ignoreUnknow
configChannel = configChannel,
abortOnConnectFail = abortOnConnectFail,
resolveDns = resolveDns,
+ protocol = protocol,
proxy = proxy,
commandMap = commandMap,
CertificateValidationCallback = CertificateValidationCallback,
@@ -727,6 +739,7 @@ public string ToString(bool includePassword)
Append(sb, OptionKeys.ResolveDns, resolveDns);
Append(sb, OptionKeys.ChannelPrefix, (string?)ChannelPrefix);
Append(sb, OptionKeys.ConnectRetry, connectRetry);
+ Append(sb, OptionKeys.Protocol, protocol);
Append(sb, OptionKeys.Proxy, proxy);
Append(sb, OptionKeys.ConfigCheckSeconds, configCheckSeconds);
Append(sb, OptionKeys.ResponseTimeout, responseTimeout);
@@ -874,6 +887,9 @@ private ConfigurationOptions DoParse(string configuration, bool ignoreUnknown)
case OptionKeys.SslHost:
SslHost = value;
break;
+ case OptionKeys.Protocol:
+ Protocol = value;
+ break;
case OptionKeys.Proxy:
Proxy = OptionKeys.ParseProxy(key, value);
break;
diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.cs b/src/StackExchange.Redis/ConnectionMultiplexer.cs
index b94e4650b..30037867e 100644
--- a/src/StackExchange.Redis/ConnectionMultiplexer.cs
+++ b/src/StackExchange.Redis/ConnectionMultiplexer.cs
@@ -110,6 +110,11 @@ public bool IncludePerformanceCountersInExceptions
///
public string Configuration => RawConfig.ToString();
+ ///
+ /// Gets the RESP protocol in use.
+ ///
+ public string Protocol => RawConfig.Protocol;
+
///
/// Indicates whether any servers are connected.
///
diff --git a/src/StackExchange.Redis/Enums/RedisCommand.cs b/src/StackExchange.Redis/Enums/RedisCommand.cs
index 40cb5c708..b2ba34727 100644
--- a/src/StackExchange.Redis/Enums/RedisCommand.cs
+++ b/src/StackExchange.Redis/Enums/RedisCommand.cs
@@ -64,6 +64,7 @@ internal enum RedisCommand
GETSET,
HDEL,
+ HELLO,
HEXISTS,
HGET,
HGETALL,
@@ -279,6 +280,7 @@ internal static bool IsPrimaryOnly(this RedisCommand command)
case RedisCommand.GETEX:
case RedisCommand.GETSET:
case RedisCommand.HDEL:
+ case RedisCommand.HELLO:
case RedisCommand.HINCRBY:
case RedisCommand.HINCRBYFLOAT:
case RedisCommand.HMSET:
diff --git a/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs b/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs
index 583d621eb..88aae4cf6 100644
--- a/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs
+++ b/src/StackExchange.Redis/Interfaces/IConnectionMultiplexer.cs
@@ -34,6 +34,11 @@ public interface IConnectionMultiplexer : IDisposable, IAsyncDisposable
///
string Configuration { get; }
+ ///
+ /// Gets the RESP protocol in use.
+ ///
+ public string Protocol { get; }
+
///
/// Gets the timeout associated with the connections.
///
diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
index 72ae963c1..224fa7df2 100644
--- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
@@ -242,6 +242,8 @@ StackExchange.Redis.ConfigurationOptions.Password.get -> string?
StackExchange.Redis.ConfigurationOptions.Password.set -> void
StackExchange.Redis.ConfigurationOptions.PreserveAsyncOrder.get -> bool
StackExchange.Redis.ConfigurationOptions.PreserveAsyncOrder.set -> void
+StackExchange.Redis.ConfigurationOptions.Protocol.get -> string!
+StackExchange.Redis.ConfigurationOptions.Protocol.set -> void
StackExchange.Redis.ConfigurationOptions.Proxy.get -> StackExchange.Redis.Proxy
StackExchange.Redis.ConfigurationOptions.Proxy.set -> void
StackExchange.Redis.ConfigurationOptions.ReconnectRetryPolicy.get -> StackExchange.Redis.IReconnectRetryPolicy!
@@ -349,6 +351,7 @@ StackExchange.Redis.ConnectionMultiplexer.IsConnecting.get -> bool
StackExchange.Redis.ConnectionMultiplexer.OperationCount.get -> long
StackExchange.Redis.ConnectionMultiplexer.PreserveAsyncOrder.get -> bool
StackExchange.Redis.ConnectionMultiplexer.PreserveAsyncOrder.set -> void
+StackExchange.Redis.ConnectionMultiplexer.Protocol.get -> string!
StackExchange.Redis.ConnectionMultiplexer.PublishReconfigure(StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.ConnectionMultiplexer.PublishReconfigureAsync(StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.ConnectionMultiplexer.ReconfigureAsync(string! reason) -> System.Threading.Tasks.Task!
@@ -488,6 +491,7 @@ StackExchange.Redis.IConnectionMultiplexer.IsConnecting.get -> bool
StackExchange.Redis.IConnectionMultiplexer.OperationCount.get -> long
StackExchange.Redis.IConnectionMultiplexer.PreserveAsyncOrder.get -> bool
StackExchange.Redis.IConnectionMultiplexer.PreserveAsyncOrder.set -> void
+StackExchange.Redis.IConnectionMultiplexer.Protocol.get -> string!
StackExchange.Redis.IConnectionMultiplexer.PublishReconfigure(StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long
StackExchange.Redis.IConnectionMultiplexer.PublishReconfigureAsync(StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
StackExchange.Redis.IConnectionMultiplexer.RegisterProfiler(System.Func! profilingSessionProvider) -> void
@@ -1781,6 +1785,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.Protocol.get -> string!
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Proxy.get -> StackExchange.Redis.Proxy
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.ReconnectRetryPolicy.get -> StackExchange.Redis.IReconnectRetryPolicy?
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.ResolveDns.get -> bool
diff --git a/src/StackExchange.Redis/ServerEndPoint.cs b/src/StackExchange.Redis/ServerEndPoint.cs
index 1e192d85e..484da5c0a 100644
--- a/src/StackExchange.Redis/ServerEndPoint.cs
+++ b/src/StackExchange.Redis/ServerEndPoint.cs
@@ -931,6 +931,14 @@ private async Task HandshakeAsync(PhysicalConnection connection, LogProxy? log)
}
}
+ if (Multiplexer.Protocol == "3")
+ {
+ log?.WriteLine($"{Format.ToString(this)}: Setting RESP protocol to RESP {Multiplexer.Protocol}");
+ msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.HELLO, (RedisValue)Multiplexer.Protocol);
+ msg.SetInternalCall();
+ await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait();
+ }
+
var bridge = connection.BridgeCouldBeNull;
if (bridge == null)
{
diff --git a/tests/StackExchange.Redis.Tests/ConfigTests.cs b/tests/StackExchange.Redis.Tests/ConfigTests.cs
index 668abe607..23f2c19ce 100644
--- a/tests/StackExchange.Redis.Tests/ConfigTests.cs
+++ b/tests/StackExchange.Redis.Tests/ConfigTests.cs
@@ -458,6 +458,20 @@ public void ThreadPoolManagerIsDetected()
Assert.Same(PipeScheduler.ThreadPool, conn.SocketManager?.Scheduler);
}
+ [Fact]
+ public void Resp3Test()
+ {
+ var config = new ConfigurationOptions
+ {
+ Protocol = "3"
+ };
+
+ var conn = ConnectionMultiplexer.Connect(config);
+ var db = conn.GetDatabase();
+ db.Ping();
+ db.Ping();
+ }
+
[Fact]
public void DefaultThreadPoolManagerIsDetected()
{
diff --git a/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs b/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs
index aec2e0a83..5f6e7cbb3 100644
--- a/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs
+++ b/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs
@@ -59,6 +59,8 @@ public bool IgnoreConnect
public string Configuration => _inner.Configuration;
+ public string Protocol => _inner.Protocol;
+
public int TimeoutMilliseconds => _inner.TimeoutMilliseconds;
public long OperationCount => _inner.OperationCount;