From b56e707aba039edc05de06ddbab767d1347038f0 Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 23 Mar 2020 13:14:45 +0000 Subject: [PATCH 1/3] fix naming of SentinelGetSentinelAddressesAsync --- src/StackExchange.Redis/ConnectionMultiplexer.cs | 2 +- src/StackExchange.Redis/Interfaces/IServer.cs | 11 ++++++++++- src/StackExchange.Redis/RedisServer.cs | 10 ++++++++-- tests/StackExchange.Redis.Tests/Sentinel.cs | 6 +++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.cs b/src/StackExchange.Redis/ConnectionMultiplexer.cs index 9f6fceb68..142b27152 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.cs @@ -2423,7 +2423,7 @@ internal void UpdateSentinelAddressList(string serviceName, int timeoutmillis = { Task[] sentinels = GetServerSnapshot().ToArray() .Where(s => s.ServerType == ServerType.Sentinel) - .Select(s => GetServer(s.EndPoint).SentinelGetSentinelAddresses(serviceName)) + .Select(s => GetServer(s.EndPoint).SentinelGetSentinelAddressesAsync(serviceName)) .ToArray(); Task> firstCompleteRequest = WaitFirstNonNullIgnoreErrorsAsync(sentinels); diff --git a/src/StackExchange.Redis/Interfaces/IServer.cs b/src/StackExchange.Redis/Interfaces/IServer.cs index 8bd576453..bd8f8fcdf 100644 --- a/src/StackExchange.Redis/Interfaces/IServer.cs +++ b/src/StackExchange.Redis/Interfaces/IServer.cs @@ -759,7 +759,16 @@ public partial interface IServer : IRedis /// the sentinel service name /// /// a list of the sentinel ips and ports - Task SentinelGetSentinelAddresses(string serviveName, CommandFlags flags = CommandFlags.None); + EndPoint[] SentinelGetSentinelAddresses(string serviveName, CommandFlags flags = CommandFlags.None); + + /// + /// Returns the ip and port numbers of all known Sentinels + /// for the given service name. + /// + /// the sentinel service name + /// + /// a list of the sentinel ips and ports + Task SentinelGetSentinelAddressesAsync(string serviveName, CommandFlags flags = CommandFlags.None); /// /// Show the state and info of the specified master. diff --git a/src/StackExchange.Redis/RedisServer.cs b/src/StackExchange.Redis/RedisServer.cs index 1ab799af3..f66236d85 100644 --- a/src/StackExchange.Redis/RedisServer.cs +++ b/src/StackExchange.Redis/RedisServer.cs @@ -807,10 +807,16 @@ public Task SentinelGetMasterAddressByNameAsync(string serviceName, Co return ExecuteAsync(msg, ResultProcessor.SentinelMasterEndpoint); } - public Task SentinelGetSentinelAddresses(string serviceName, CommandFlags flags = CommandFlags.None) + public EndPoint[] SentinelGetSentinelAddresses(string serviceName, CommandFlags flags = CommandFlags.None) { var msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.SENTINELS, (RedisValue)serviceName); - return ExecuteAsync(msg, ResultProcessor.SentinelAddressesEndPoints); + return ExecuteSync(msg, ResultProcessor.SentinelAddressesEndPoints); + } + + public Task SentinelGetSentinelAddressesAsync(string serviceName, CommandFlags flags = CommandFlags.None) + { + var msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.SENTINELS, (RedisValue)serviceName); + return ExecuteAsync(msg, ResultProcessor.SentinelAddressesEndPoints); } public KeyValuePair[] SentinelMaster(string serviceName, CommandFlags flags = CommandFlags.None) diff --git a/tests/StackExchange.Redis.Tests/Sentinel.cs b/tests/StackExchange.Redis.Tests/Sentinel.cs index 65da27a51..aec7380ab 100644 --- a/tests/StackExchange.Redis.Tests/Sentinel.cs +++ b/tests/StackExchange.Redis.Tests/Sentinel.cs @@ -562,15 +562,15 @@ await UntilCondition(TimeSpan.FromSeconds(20), () => [Fact] public async Task SentinelGetSentinelAddressesTest() { - var addresses = await SentinelServerA.SentinelGetSentinelAddresses(ServiceName).ForAwait(); + var addresses = await SentinelServerA.SentinelGetSentinelAddressesAsync(ServiceName).ForAwait(); Assert.Contains(SentinelServerB.EndPoint, addresses); Assert.Contains(SentinelServerC.EndPoint, addresses); - addresses = await SentinelServerB.SentinelGetSentinelAddresses(ServiceName).ForAwait(); + addresses = await SentinelServerB.SentinelGetSentinelAddressesAsync(ServiceName).ForAwait(); Assert.Contains(SentinelServerA.EndPoint, addresses); Assert.Contains(SentinelServerC.EndPoint, addresses); - addresses = await SentinelServerC.SentinelGetSentinelAddresses(ServiceName).ForAwait(); + addresses = await SentinelServerC.SentinelGetSentinelAddressesAsync(ServiceName).ForAwait(); Assert.Contains(SentinelServerA.EndPoint, addresses); Assert.Contains(SentinelServerB.EndPoint, addresses); } From b3082ab3854c669e228e419709567ddb6c487b1b Mon Sep 17 00:00:00 2001 From: mgravell Date: Mon, 23 Mar 2020 13:20:17 +0000 Subject: [PATCH 2/3] tyop --- src/StackExchange.Redis/Interfaces/IServer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/StackExchange.Redis/Interfaces/IServer.cs b/src/StackExchange.Redis/Interfaces/IServer.cs index bd8f8fcdf..2064b6405 100644 --- a/src/StackExchange.Redis/Interfaces/IServer.cs +++ b/src/StackExchange.Redis/Interfaces/IServer.cs @@ -756,19 +756,19 @@ public partial interface IServer : IRedis /// Returns the ip and port numbers of all known Sentinels /// for the given service name. /// - /// the sentinel service name + /// the sentinel service name /// /// a list of the sentinel ips and ports - EndPoint[] SentinelGetSentinelAddresses(string serviveName, CommandFlags flags = CommandFlags.None); + EndPoint[] SentinelGetSentinelAddresses(string serviceName, CommandFlags flags = CommandFlags.None); /// /// Returns the ip and port numbers of all known Sentinels /// for the given service name. /// - /// the sentinel service name + /// the sentinel service name /// /// a list of the sentinel ips and ports - Task SentinelGetSentinelAddressesAsync(string serviveName, CommandFlags flags = CommandFlags.None); + Task SentinelGetSentinelAddressesAsync(string serviceName, CommandFlags flags = CommandFlags.None); /// /// Show the state and info of the specified master. From f3d0c6932fdfaf60b61cfe7c4ff1c2defc19ca3e Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Mon, 23 Mar 2020 09:29:48 -0400 Subject: [PATCH 3/3] Sentinel: don't use async over sync with .Result --- .../ConnectionMultiplexer.cs | 73 ++++--------------- 1 file changed, 16 insertions(+), 57 deletions(-) diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.cs b/src/StackExchange.Redis/ConnectionMultiplexer.cs index 142b27152..607b70f39 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.cs @@ -2303,53 +2303,16 @@ internal void OnManagedConnectionFailed(object sender, ConnectionFailedEventArgs { SwitchMaster(e.EndPoint, connection); }, null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1)); - - //connection.sentinelMasterReconnectTimer.AutoReset = true; - - //connection.sentinelMasterReconnectTimer.Start(); } } - internal EndPoint GetConfiguredMasterForService(string serviceName, int timeoutmillis = -1) - { - Task[] sentinelMasters = GetServerSnapshot().ToArray() - .Where(s => s.ServerType == ServerType.Sentinel) - .Select(s => GetServer(s.EndPoint).SentinelGetMasterAddressByNameAsync(serviceName)) - .ToArray(); - - Task> firstCompleteRequest = WaitFirstNonNullIgnoreErrorsAsync(sentinelMasters); - if (!firstCompleteRequest.Wait(timeoutmillis)) - throw new TimeoutException("Timeout resolving master for service"); - if (firstCompleteRequest.Result.Result == null) - throw new Exception("Unable to determine master"); - - return firstCompleteRequest.Result.Result; - } - - private static async Task> WaitFirstNonNullIgnoreErrorsAsync(Task[] tasks) - { - if (tasks == null) throw new ArgumentNullException("tasks"); - if (tasks.Length == 0) return null; - var typeNullable = (Nullable.GetUnderlyingType(typeof(T)) != null); - var taskList = tasks.Cast().ToList(); - - try - { - while (taskList.Count > 0) - { - var allTasksAwaitingAny = Task.WhenAny(taskList).ObserveErrors(); - var result = await allTasksAwaitingAny.ForAwait(); - taskList.Remove((Task)result); - if (((Task)result).IsFaulted) continue; - if ((!typeNullable) || ((Task)result).Result != null) - return (Task)result; - } - } - catch - { } - - return null; - } + internal EndPoint GetConfiguredMasterForService(string serviceName) => + GetServerSnapshot() + .ToArray() + .Where(s => s.ServerType == ServerType.Sentinel) + .AsParallel() + .Select(s => GetServer(s.EndPoint).SentinelGetMasterAddressByName(serviceName)) + .First(r => r != null); internal EndPoint currentSentinelMasterEndPoint; @@ -2419,26 +2382,22 @@ private T Retry(int times, int interval, Func func, string message) throw new NullReferenceException(message); } - internal void UpdateSentinelAddressList(string serviceName, int timeoutmillis = 500) + internal void UpdateSentinelAddressList(string serviceName) { - Task[] sentinels = GetServerSnapshot().ToArray() - .Where(s => s.ServerType == ServerType.Sentinel) - .Select(s => GetServer(s.EndPoint).SentinelGetSentinelAddressesAsync(serviceName)) - .ToArray(); - - Task> firstCompleteRequest = WaitFirstNonNullIgnoreErrorsAsync(sentinels); + var firstCompleteRequest = GetServerSnapshot() + .ToArray() + .Where(s => s.ServerType == ServerType.Sentinel) + .AsParallel() + .Select(s => GetServer(s.EndPoint).SentinelGetSentinelAddresses(serviceName)) + .First(r => r != null); // Ignore errors, as having an updated sentinel list is // not essential - if (firstCompleteRequest.Result?.Result == null) - return; - if (!firstCompleteRequest.Wait(timeoutmillis)) - return; - if (firstCompleteRequest.Result.Result == null) + if (firstCompleteRequest == null) return; bool hasNew = false; - foreach (EndPoint newSentinel in firstCompleteRequest.Result.Result.Where(x => !RawConfig.EndPoints.Contains(x))) + foreach (EndPoint newSentinel in firstCompleteRequest.Where(x => !RawConfig.EndPoints.Contains(x))) { hasNew = true; RawConfig.EndPoints.Add(newSentinel);