From 50cf00fa14c6c7fd9d4cb6043724d3b6ea9b1bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=88=E6=98=9F=E7=B9=81?= Date: Thu, 19 Nov 2020 15:20:06 +0800 Subject: [PATCH 1/3] fix: prevent pool size exceeds --- .../Implementations/RedisCacheConnectionPoolManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs b/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs index 3502af12..5cbb45ea 100644 --- a/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs +++ b/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs @@ -26,9 +26,9 @@ public class RedisCacheConnectionPoolManager : IRedisCacheConnectionPoolManager public RedisCacheConnectionPoolManager(RedisConfiguration redisConfiguration, ILogger logger = null) { this.redisConfiguration = redisConfiguration ?? throw new ArgumentNullException(nameof(redisConfiguration)); - this.connections = new ConcurrentBag>(); this.logger = logger ?? NullLogger.Instance; + this.EmitConnections(); } /// @@ -46,8 +46,6 @@ public void Dispose() /// public IConnectionMultiplexer GetConnection() { - this.EmitConnections(); - var loadedLazies = this.connections.Where(lazy => lazy.IsValueCreated); if (loadedLazies.Count() == this.connections.Count) From ab8a9166616785e74ced79c6312c185276175903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=88=E6=98=9F=E7=B9=81?= Date: Thu, 19 Nov 2020 17:57:28 +0800 Subject: [PATCH 2/3] fix: initialize all connection at once --- Directory.Build.props | 5 +- .../RedisCacheConnectionPoolManager.cs | 68 ++++++++----------- 2 files changed, 30 insertions(+), 43 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index cbbd71dd..abde96fa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,10 +4,9 @@ Ugo Lattanzi - 6.3.5 - + netstandard2.0;netcoreapp3.0;netcoreapp3.1 True diff --git a/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs b/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs index 5cbb45ea..58bebce8 100644 --- a/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs +++ b/src/core/StackExchange.Redis.Extensions.Core/Implementations/RedisCacheConnectionPoolManager.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -14,7 +16,7 @@ namespace StackExchange.Redis.Extensions.Core.Implementations /// public class RedisCacheConnectionPoolManager : IRedisCacheConnectionPoolManager { - private readonly ConcurrentBag> connections; + private readonly ConcurrentBag connections; private readonly RedisConfiguration redisConfiguration; private readonly ILogger logger; @@ -26,7 +28,7 @@ public class RedisCacheConnectionPoolManager : IRedisCacheConnectionPoolManager public RedisCacheConnectionPoolManager(RedisConfiguration redisConfiguration, ILogger logger = null) { this.redisConfiguration = redisConfiguration ?? throw new ArgumentNullException(nameof(redisConfiguration)); - this.connections = new ConcurrentBag>(); + this.connections = new ConcurrentBag(); this.logger = logger ?? NullLogger.Instance; this.EmitConnections(); } @@ -34,10 +36,8 @@ public RedisCacheConnectionPoolManager(RedisConfiguration redisConfiguration, IL /// public void Dispose() { - var activeConnections = this.connections.Where(lazy => lazy.IsValueCreated).ToList(); - - foreach (var connection in activeConnections) - connection.Value.Dispose(); + foreach (var connection in connections) + connection.Dispose(); while (this.connections.IsEmpty == false) this.connections.TryTake(out var taken); @@ -46,12 +46,12 @@ public void Dispose() /// public IConnectionMultiplexer GetConnection() { - var loadedLazies = this.connections.Where(lazy => lazy.IsValueCreated); - - if (loadedLazies.Count() == this.connections.Count) - return this.connections.OrderBy(x => x.Value.TotalOutstanding()).First().Value.Connection; + if (this.connections.IsEmpty == false) + { + return this.connections.OrderBy(c => c.TotalOutstanding()).First().Connection; + } - return this.connections.First(lazy => !lazy.IsValueCreated).Value.Connection; + throw new Exception("no connection available"); } /// @@ -59,17 +59,10 @@ public ConnectionPoolInformation GetConnectionInformations() { var activeConnections = 0; var invalidConnections = 0; - var readyNotUsedYet = 0; foreach (var lazy in connections) { - if (!lazy.IsValueCreated) - { - readyNotUsedYet++; - continue; - } - - if (!lazy.Value.IsConnected()) + if (!lazy.IsConnected()) { invalidConnections++; continue; @@ -83,35 +76,30 @@ public ConnectionPoolInformation GetConnectionInformations() RequiredPoolSize = redisConfiguration.PoolSize, ActiveConnections = activeConnections, InvalidConnections = invalidConnections, - ReadyNotUsedYet = readyNotUsedYet + ReadyNotUsedYet = 0 }; } - private void EmitConnection() + private Task EmitConnection() { - this.connections.Add(new Lazy(() => - { - this.logger.LogDebug("Creating new Redis connection."); - - var multiplexer = ConnectionMultiplexer.Connect(redisConfiguration.ConfigurationOptions); - - if (this.redisConfiguration.ProfilingSessionProvider != null) - multiplexer.RegisterProfiler(this.redisConfiguration.ProfilingSessionProvider); - - return this.redisConfiguration.StateAwareConnectionFactory(multiplexer, logger); - })); + return Task.Run( + async () => + { + this.logger.LogDebug("Creating new Redis connection."); + var multiplexer = await ConnectionMultiplexer.ConnectAsync(redisConfiguration.ConfigurationOptions); + if (this.redisConfiguration.ProfilingSessionProvider != null) + multiplexer.RegisterProfiler(this.redisConfiguration.ProfilingSessionProvider); + this.connections.Add(this.redisConfiguration.StateAwareConnectionFactory(multiplexer, logger)); + }); } private void EmitConnections() { - if (connections.Count >= this.redisConfiguration.PoolSize) - return; - - for (var i = 0; i < this.redisConfiguration.PoolSize; i++) - { - logger.LogDebug("Creating the redis connection pool with {0} connections.", this.redisConfiguration.PoolSize); - this.EmitConnection(); - } + logger.LogDebug("Creating the redis connection pool with {0} connections.", this.redisConfiguration.PoolSize); + var tasks = Enumerable.Range(0, this.redisConfiguration.PoolSize) + .Select(_ => this.EmitConnection()) + .ToArray(); + Task.WaitAny(tasks); // wait for at least 1 connection to be available } /// From a363a3edc995aa71d72f2671645054f7d97f9527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=88=E6=98=9F=E7=B9=81?= Date: Thu, 19 Nov 2020 18:08:00 +0800 Subject: [PATCH 3/3] fix: initialize all connection at once --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index abde96fa..466b91ba 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ Ugo Lattanzi - 6.3.6 + 6.3.7 pre