diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DistributedCacheClientCache.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DistributedCacheClientCache.cs new file mode 100644 index 000000000..4b23a2efa --- /dev/null +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/DistributedCacheClientCache.cs @@ -0,0 +1,21 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Caching; + +internal class DistributedCacheClientCache +{ + public static ConcurrentDictionary CacheClients { get; set; } = new(); + + public IManualDistributedCacheClient GetCacheClient(IServiceProvider serviceProvider) + { + var multiEnvironmentContext = serviceProvider.GetRequiredService(); + var environment = multiEnvironmentContext.CurrentEnvironment; + + return CacheClients.GetOrAdd(environment, env => + { + var cacheClient = serviceProvider.GetRequiredService>().Service; + return cacheClient; + }); + } +} diff --git a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs index 67ed3f85b..25c475013 100644 --- a/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs +++ b/src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs @@ -23,8 +23,9 @@ public static void TryAddDistributedCache( services.TryAddTransient(serviceProvider => { var cacheClient = serviceProvider.EnableIsolation() ? - serviceProvider.GetRequiredService>().Service : + serviceProvider.GetRequiredService().GetCacheClient(serviceProvider) : serviceProvider.GetRequiredService>().Service; + return new DefaultDistributedCacheClient(cacheClient); }); services.TryAddTransient(serviceProvider @@ -65,6 +66,8 @@ private static void AddTypeAlias( private static void AddCaching(this IServiceCollection services) { + services.TryAddSingleton(); + services.TryAddSingleton>(serviceProvider => new SingletonService(serviceProvider.GetRequiredService() .Create())); diff --git a/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs b/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs index 20cf755e2..39d8272a5 100644 --- a/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs +++ b/src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs @@ -7,29 +7,29 @@ public abstract class RedisCacheClientBase : DistributedCacheClientBase { protected readonly string? InstanceId; protected static readonly Guid UniquelyIdentifies = Guid.NewGuid(); - protected readonly ISubscriber Subscriber; + protected ISubscriber Subscriber; protected IDatabase Db { get { - if (_connection.IsConnected || _connection.IsConnecting) - return _connection.GetDatabase(); - - throw new NotSupportedException("Redis service has been disconnected, please wait for reconnection and try again"); + return EnsureDbConnection(); } } - private readonly IConnectionMultiplexer _connection; + private IConnectionMultiplexer _connection; protected readonly JsonSerializerOptions GlobalJsonSerializerOptions; private readonly CacheEntryOptions _globalCacheEntryOptions; private readonly CacheOptions _globalCacheOptions; + private readonly RedisConfigurationOptions _redisConfigurationOptions; + protected RedisCacheClientBase( RedisConfigurationOptions redisConfigurationOptions, JsonSerializerOptions? jsonSerializerOptions) : this(redisConfigurationOptions.GlobalCacheOptions, redisConfigurationOptions, jsonSerializerOptions) { + _redisConfigurationOptions = redisConfigurationOptions; var redisConfiguration = redisConfigurationOptions.GetAvailableRedisOptions(); _connection = ConnectionMultiplexer.Connect(redisConfiguration); Subscriber = _connection.GetSubscriber(); @@ -51,6 +51,28 @@ private RedisCacheClientBase( GlobalJsonSerializerOptions = jsonSerializerOptions ?? new JsonSerializerOptions().EnableDynamicTypes(); } + protected IDatabase EnsureDbConnection() + { + if (_connection.IsConnected || _connection.IsConnecting) + { + return _connection.GetDatabase(); + } + + // Attempt to reconnect + var redisConfiguration = _redisConfigurationOptions.GetAvailableRedisOptions(); + _connection = ConnectionMultiplexer.Connect(redisConfiguration); + Subscriber = _connection.GetSubscriber(); + + if (_connection.IsConnected || _connection.IsConnecting) + { + return _connection.GetDatabase(); + } + else + { + throw new NotSupportedException("Unable to reconnect to Redis, please check the connection settings and try again."); + } + } + protected T? ConvertToValue(RedisValue value, out bool isExist) { if (value is { HasValue: true, IsNullOrEmpty: false })