Skip to content

Commit 433b3eb

Browse files
authored
♻ refactor(IDistributedCache): Optimize connections under Isolation and Attempt to reconnect (#740)
* ♻ refactor(IDistributedCache): Optimize connections under Isolation and Attempt to reconnect * chore: TargetFrameworks * refactor: Code optimization * chore: TargetFrameworks * ♻ refactor(IDistributedCache): Support multi tenant * ♻ refactor(IDistributedCache): Code smell * ♻ refactor(IDistributedCache): Adjust the GeneratedKey method
1 parent 0aa53ec commit 433b3eb

File tree

3 files changed

+84
-6
lines changed

3 files changed

+84
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
namespace Masa.BuildingBlocks.Caching;
5+
6+
internal class DistributedCacheClientCache
7+
{
8+
private static ConcurrentDictionary<string, IManualDistributedCacheClient> _cacheClients = new();
9+
10+
public IManualDistributedCacheClient GetCacheClient(IServiceProvider serviceProvider)
11+
{
12+
var environment = GetCurrentEnvironment(serviceProvider);
13+
var tenantId = GetCurrentTenantId(serviceProvider);
14+
15+
var key = GenerateKey(environment, tenantId);
16+
17+
return _cacheClients.GetOrAdd(key, _ => CreateCacheClient(serviceProvider));
18+
}
19+
20+
private static string GetCurrentEnvironment(IServiceProvider serviceProvider)
21+
{
22+
var multiEnvironmentContext = serviceProvider.GetService<IMultiEnvironmentContext>();
23+
return multiEnvironmentContext?.CurrentEnvironment ?? string.Empty;
24+
}
25+
26+
private static string GetCurrentTenantId(IServiceProvider serviceProvider)
27+
{
28+
var multiTenantContext = serviceProvider.GetService<IMultiTenantContext>();
29+
return multiTenantContext?.CurrentTenant?.Id ?? string.Empty;
30+
}
31+
32+
private static string GenerateKey(string environment, string tenantId)
33+
{
34+
if (string.IsNullOrEmpty(environment))
35+
{
36+
return tenantId;
37+
}
38+
if (string.IsNullOrEmpty(tenantId))
39+
{
40+
return environment;
41+
}
42+
return $"{environment}:{tenantId}";
43+
}
44+
45+
private static IManualDistributedCacheClient CreateCacheClient(IServiceProvider serviceProvider)
46+
{
47+
try
48+
{
49+
var scopedService = serviceProvider.GetRequiredService<ScopedService<IManualDistributedCacheClient>>();
50+
return scopedService.Service;
51+
}
52+
catch (Exception ex)
53+
{
54+
throw new InvalidOperationException("Failed to create cache client", ex);
55+
}
56+
}
57+
}

src/BuildingBlocks/Caching/Masa.BuildingBlocks.Caching/Internal/ServiceCollectionExtensions.Core.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ public static void TryAddDistributedCache(
2323
services.TryAddTransient<IManualDistributedCacheClient>(serviceProvider =>
2424
{
2525
var cacheClient = serviceProvider.EnableIsolation() ?
26-
serviceProvider.GetRequiredService<ScopedService<IManualDistributedCacheClient>>().Service :
26+
serviceProvider.GetRequiredService<DistributedCacheClientCache>().GetCacheClient(serviceProvider) :
2727
serviceProvider.GetRequiredService<SingletonService<IManualDistributedCacheClient>>().Service;
28+
2829
return new DefaultDistributedCacheClient(cacheClient);
2930
});
3031
services.TryAddTransient<IDistributedCacheClient>(serviceProvider
@@ -65,6 +66,8 @@ private static void AddTypeAlias(
6566

6667
private static void AddCaching(this IServiceCollection services)
6768
{
69+
services.TryAddSingleton<DistributedCacheClientCache>();
70+
6871
services.TryAddSingleton<SingletonService<IManualDistributedCacheClient>>(serviceProvider =>
6972
new SingletonService<IManualDistributedCacheClient>(serviceProvider.GetRequiredService<IDistributedCacheClientFactory>()
7073
.Create()));

src/Contrib/Caching/Distributed/Masa.Contrib.Caching.Distributed.StackExchangeRedis/RedisCacheClientBase.cs

+23-5
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,31 @@ public abstract class RedisCacheClientBase : DistributedCacheClientBase
77
{
88
protected readonly string? InstanceId;
99
protected static readonly Guid UniquelyIdentifies = Guid.NewGuid();
10-
protected readonly ISubscriber Subscriber;
10+
protected ISubscriber Subscriber;
1111

1212
protected IDatabase Db
1313
{
1414
get
1515
{
16-
if (_connection.IsConnected || _connection.IsConnecting)
17-
return _connection.GetDatabase();
16+
EnsureDbConnection();
1817

19-
throw new NotSupportedException("Redis service has been disconnected, please wait for reconnection and try again");
18+
return _connection.GetDatabase();
2019
}
2120
}
2221

23-
private readonly IConnectionMultiplexer _connection;
22+
private IConnectionMultiplexer _connection;
2423
protected readonly JsonSerializerOptions GlobalJsonSerializerOptions;
2524
private readonly CacheEntryOptions _globalCacheEntryOptions;
2625
private readonly CacheOptions _globalCacheOptions;
2726

27+
private readonly RedisConfigurationOptions _redisConfigurationOptions;
28+
2829
protected RedisCacheClientBase(
2930
RedisConfigurationOptions redisConfigurationOptions,
3031
JsonSerializerOptions? jsonSerializerOptions)
3132
: this(redisConfigurationOptions.GlobalCacheOptions, redisConfigurationOptions, jsonSerializerOptions)
3233
{
34+
_redisConfigurationOptions = redisConfigurationOptions;
3335
var redisConfiguration = redisConfigurationOptions.GetAvailableRedisOptions();
3436
_connection = ConnectionMultiplexer.Connect(redisConfiguration);
3537
Subscriber = _connection.GetSubscriber();
@@ -51,6 +53,22 @@ private RedisCacheClientBase(
5153
GlobalJsonSerializerOptions = jsonSerializerOptions ?? new JsonSerializerOptions().EnableDynamicTypes();
5254
}
5355

56+
protected void EnsureDbConnection()
57+
{
58+
if (!_connection.IsConnected && !_connection.IsConnecting)
59+
{
60+
// Attempt to reconnect
61+
var redisConfiguration = _redisConfigurationOptions.GetAvailableRedisOptions();
62+
_connection = ConnectionMultiplexer.Connect(redisConfiguration);
63+
Subscriber = _connection.GetSubscriber();
64+
}
65+
66+
if (!_connection.IsConnected && !_connection.IsConnecting)
67+
{
68+
throw new NotSupportedException("Unable to reconnect to Redis, please check the connection settings and try again.");
69+
}
70+
}
71+
5472
protected T? ConvertToValue<T>(RedisValue value, out bool isExist)
5573
{
5674
if (value is { HasValue: true, IsNullOrEmpty: false })

0 commit comments

Comments
 (0)