Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 7912833

Browse files
committed
Add new overridable RedisManagerFactory to RedisSentinel with configurable OnInit filter
1 parent 51efbdc commit 7912833

File tree

6 files changed

+112
-57
lines changed

6 files changed

+112
-57
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace ServiceStack.Redis
6+
{
7+
public class RedisManagerFactory
8+
{
9+
public Action<IRedisClientsManager> OnInit { get; set; }
10+
11+
public Func<IEnumerable<string>, IEnumerable<string>, IRedisClientsManager> FactoryFn { get; set; }
12+
13+
public RedisManagerFactory()
14+
{
15+
FactoryFn = CreatePooledRedisClientManager;
16+
}
17+
18+
public static IRedisClientsManager CreatePooledRedisClientManager(
19+
IEnumerable<string> readWriteHosts,
20+
IEnumerable<string> readOnlyHosts)
21+
{
22+
return readOnlyHosts.Any()
23+
? new PooledRedisClientManager(readWriteHosts, readOnlyHosts)
24+
: new PooledRedisClientManager(readWriteHosts.ToArray());
25+
}
26+
27+
public static IRedisClientsManager CreateBasicRedisClientManager(
28+
IEnumerable<string> readWriteHosts,
29+
IEnumerable<string> readOnlyHosts)
30+
{
31+
return readOnlyHosts.Any()
32+
? new BasicRedisClientManager(readWriteHosts, readOnlyHosts)
33+
: new BasicRedisClientManager(readWriteHosts.ToArray());
34+
}
35+
36+
public static IRedisClientsManager CreateRedisManager(
37+
IEnumerable<string> readWriteHosts,
38+
IEnumerable<string> readOnlyHosts)
39+
{
40+
return new RedisManagerPool(readWriteHosts);
41+
}
42+
43+
public IRedisClientsManager Create(IEnumerable<string> readWriteHosts, IEnumerable<string> readOnlyHosts)
44+
{
45+
var redisManager = FactoryFn(readWriteHosts, readOnlyHosts);
46+
if (OnInit != null)
47+
OnInit(redisManager);
48+
49+
return redisManager;
50+
}
51+
}
52+
}

src/ServiceStack.Redis/RedisSentinel.cs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,32 @@
55
// Upon a s_down event, the RedisClientsManager will be failed over to the new set of slaves/masters
66
//
77

8-
using ServiceStack;
9-
using ServiceStack.Redis;
108
using System;
119
using System.Collections.Generic;
12-
using System.Diagnostics;
1310
using System.Linq;
14-
using System.Threading.Tasks;
15-
using System.Web;
1611

1712
namespace ServiceStack.Redis
1813
{
1914
public class RedisSentinel : IRedisSentinel
2015
{
16+
public RedisManagerFactory RedisManagerFactory { get; set; }
17+
2118
private readonly string sentinelName;
2219
private int failures = 0;
2320
private int sentinelIndex = -1;
2421
private List<string> sentinels;
2522
private RedisSentinelWorker worker;
26-
private PooledRedisClientManager clientManager;
23+
internal IRedisClientsManager redisManager;
2724
private static int MaxFailures = 5;
2825

2926
public RedisSentinel(IEnumerable<string> sentinelHosts, string sentinelName)
3027
{
31-
if (sentinelHosts == null || sentinelHosts.Count() == 0) throw new ArgumentException("sentinels must have at least one entry");
28+
this.sentinels = sentinelHosts != null ? sentinelHosts.ToList() : null;
29+
if (sentinelHosts == null || sentinels.Count == 0)
30+
throw new ArgumentException("sentinels must have at least one entry");
3231

3332
this.sentinelName = sentinelName;
34-
this.sentinels = new List<string>(sentinelHosts);
33+
this.RedisManagerFactory = new RedisManagerFactory();
3534
}
3635

3736
/// <summary>
@@ -42,22 +41,22 @@ public IRedisClientsManager Setup()
4241
{
4342
GetValidSentinel();
4443

45-
if (this.clientManager == null)
44+
if (this.redisManager == null)
4645
{
4746
throw new ApplicationException("Unable to resolve sentinels!");
4847
}
4948

50-
return this.clientManager;
49+
return this.redisManager;
5150
}
5251

5352
private void GetValidSentinel()
5453
{
55-
while (this.clientManager == null && ShouldRetry())
54+
while (this.redisManager == null && ShouldRetry())
5655
{
5756
try
5857
{
5958
this.worker = GetNextSentinel();
60-
this.clientManager = worker.GetClientManager();
59+
this.redisManager = worker.GetClientManager();
6160
this.worker.BeginListeningForConfigurationChanges();
6261
}
6362
catch (RedisException)
@@ -80,7 +79,7 @@ private void GetValidSentinel()
8079
/// <remarks>This will be true if the failures is less than either RedisSentinel.MaxFailures or the # of sentinels, whatever is greater</remarks>
8180
private bool ShouldRetry()
8281
{
83-
return this.failures < Math.Max(RedisSentinel.MaxFailures, this.sentinels.Count);
82+
return this.failures < Math.Max(MaxFailures, this.sentinels.Count);
8483
}
8584

8685
private RedisSentinelWorker GetNextSentinel()
@@ -92,7 +91,7 @@ private RedisSentinelWorker GetNextSentinel()
9291
sentinelIndex = 0;
9392
}
9493

95-
var sentinelWorker = new RedisSentinelWorker(sentinels[sentinelIndex], this.sentinelName, this.clientManager);
94+
var sentinelWorker = new RedisSentinelWorker(this, sentinels[sentinelIndex], this.sentinelName);
9695

9796
sentinelWorker.SentinelError += Worker_SentinelError;
9897
return sentinelWorker;

src/ServiceStack.Redis/RedisSentinelWorker.cs

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,35 @@
1-
using ServiceStack;
2-
using ServiceStack.Logging;
3-
using ServiceStack.Redis;
1+
using ServiceStack.Logging;
42
using System;
53
using System.Collections.Generic;
6-
using System.Diagnostics;
7-
using System.IO;
84
using System.Linq;
95
using System.Text;
106
using System.Threading.Tasks;
11-
using System.Web;
127

138
namespace ServiceStack.Redis
149
{
1510
internal class RedisSentinelWorker : IDisposable
1611
{
1712
protected static readonly ILog Log = LogManager.GetLogger(typeof(RedisSentinelWorker));
1813

19-
private RedisClient sentinelClient;
20-
private RedisClient sentinelPubSubClient;
21-
private PooledRedisClientManager clientsManager;
22-
private IRedisSubscription sentinelSubscription;
23-
private string sentinelName;
14+
private readonly RedisSentinel redisSentinel;
15+
private readonly RedisClient sentinelClient;
16+
private readonly RedisClient sentinelPubSubClient;
17+
private readonly IRedisSubscription sentinelSubscription;
18+
private readonly string sentinelName;
2419
private string host;
20+
private IRedisClientsManager redisManager;
2521

2622
public event EventHandler SentinelError;
2723

28-
public RedisSentinelWorker(string host, string sentinelName, PooledRedisClientManager clientsManager = null)
24+
public RedisSentinelWorker(RedisSentinel redisSentinel, string host, string sentinelName)
2925
{
26+
this.redisSentinel = redisSentinel;
27+
this.redisManager = redisSentinel.redisManager;
3028
this.sentinelName = sentinelName;
3129
this.sentinelClient = new RedisClient(host);
3230
this.sentinelPubSubClient = new RedisClient(host);
3331
this.sentinelSubscription = this.sentinelPubSubClient.CreateSubscription();
3432
this.sentinelSubscription.OnMessage = SentinelMessageReceived;
35-
this.clientsManager = clientsManager;
3633

3734
Log.Info("Set up Redis Sentinel on {0}".Fmt(host));
3835
}
@@ -81,33 +78,19 @@ private void ConfigureRedisFromSentinel()
8178
var masters = ConvertMasterArrayToList(this.sentinelClient.Sentinel("master", this.sentinelName));
8279
var slaves = ConvertSlaveArrayToList(this.sentinelClient.Sentinel("slaves", this.sentinelName));
8380

84-
if (this.clientsManager == null)
81+
if (redisManager == null)
8582
{
86-
if (slaves.Count() > 0)
87-
{
88-
this.clientsManager = new PooledRedisClientManager(masters, slaves);
89-
}
90-
else
91-
{
92-
this.clientsManager = new PooledRedisClientManager(masters.ToArray());
93-
}
83+
redisManager = redisSentinel.RedisManagerFactory.Create(masters, slaves);
9484
}
9585
else
9686
{
97-
if (slaves.Count() > 0)
98-
{
99-
this.clientsManager.FailoverTo(masters, slaves);
100-
}
101-
else
102-
{
103-
this.clientsManager.FailoverTo(masters.ToArray());
104-
}
87+
((IRedisFailover)redisManager).FailoverTo(masters, slaves);
10588
}
10689
}
10790

10891
private Dictionary<string, string> ParseDataArray(object[] items)
10992
{
110-
Dictionary<string, string> data = new Dictionary<string, string>();
93+
var data = new Dictionary<string, string>();
11194
bool isKey = false;
11295
string key = null;
11396
string value = null;
@@ -142,7 +125,7 @@ private Dictionary<string, string> ParseDataArray(object[] items)
142125
/// </summary>
143126
/// <param name="items"></param>
144127
/// <returns></returns>
145-
private IEnumerable<string> ConvertSlaveArrayToList(object[] slaves)
128+
private List<string> ConvertSlaveArrayToList(object[] slaves)
146129
{
147130
var servers = new List<string>();
148131
string ip = null;
@@ -176,7 +159,7 @@ private IEnumerable<string> ConvertSlaveArrayToList(object[] slaves)
176159
/// </summary>
177160
/// <param name="items"></param>
178161
/// <returns></returns>
179-
private IEnumerable<string> ConvertMasterArrayToList(object[] items)
162+
private List<string> ConvertMasterArrayToList(object[] items)
180163
{
181164
var servers = new List<string>();
182165
string ip = null;
@@ -195,11 +178,11 @@ private IEnumerable<string> ConvertMasterArrayToList(object[] items)
195178
return servers;
196179
}
197180

198-
public PooledRedisClientManager GetClientManager()
181+
public IRedisClientsManager GetClientManager()
199182
{
200183
ConfigureRedisFromSentinel();
201184

202-
return this.clientsManager;
185+
return this.redisManager;
203186
}
204187

205188
public void Dispose()

src/ServiceStack.Redis/ServiceStack.Redis.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
<Compile Include="Commands.cs" />
152152
<Compile Include="ConnectionUtils.cs" />
153153
<Compile Include="IHandleClientDispose.cs" />
154+
<Compile Include="RedisManagerFactory.cs" />
154155
<Compile Include="RedisManagerPool.cs" />
155156
<Compile Include="RedisClient_Admin.cs" />
156157
<Compile Include="Generic\ManagedListGeneric.cs" />

tests/ServiceStack.Redis.Tests/RedisSentinelTests.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
1+
using System.Linq;
42
using System.Text;
53
using NUnit.Framework;
64

@@ -18,7 +16,7 @@ public override void OnBeforeEachTest()
1816
{
1917
base.OnBeforeEachTest();
2018

21-
RedisSentinel = new RedisClient(TestConfig.SingleHost, TestConfig.RedisSentinelPort);
19+
RedisSentinel = new RedisClient(TestConfig.SentinelHost, TestConfig.RedisSentinelPort);
2220
}
2321

2422

@@ -49,7 +47,7 @@ public void Can_Get_Sentinel_Slaves()
4947
{
5048
object[] slaves = RedisSentinel.Sentinel("slaves", TestConfig.MasterName);
5149

52-
Assert.AreEqual(slaves.Count(), TestConfig.SlaveHosts.Count());
50+
Assert.That(slaves.Count(), Is.GreaterThan(0));
5351
}
5452

5553
[Test]
@@ -60,23 +58,44 @@ public void Can_Get_Master_Addr()
6058
string host = Encoding.UTF8.GetString((byte[])addr[0]);
6159
string port = Encoding.UTF8.GetString((byte[])addr[1]);
6260

63-
Assert.AreEqual(host, "127.0.0.1"); // IP of localhost
61+
// IP of localhost
62+
Assert.That(host, Is.EqualTo("127.0.0.1").Or.EqualTo(TestConfig.SentinelHost));
6463
Assert.AreEqual(port, TestConfig.RedisPort.ToString());
6564
}
6665

6766
[Test]
6867
public void Can_Get_Redis_ClientsManager()
6968
{
70-
var sentinel = new RedisSentinel(new[] { "{0}:{1}".Fmt(TestConfig.SingleHost, TestConfig.RedisSentinelPort) }, TestConfig.MasterName);
69+
var sentinel = new RedisSentinel(new[] { "{0}:{1}".Fmt(TestConfig.SentinelHost, TestConfig.RedisSentinelPort) }, TestConfig.MasterName);
7170

7271
var clientsManager = sentinel.Setup();
7372
var client = clientsManager.GetClient();
7473

75-
Assert.AreEqual(client.Host, "127.0.0.1");
74+
Assert.That(client.Host, Is.EqualTo("127.0.0.1").Or.EqualTo(TestConfig.SentinelHost));
7675
Assert.AreEqual(client.Port, TestConfig.RedisPort);
7776

7877
client.Dispose();
7978
sentinel.Dispose();
8079
}
80+
81+
[Test]
82+
public void Can_specify_Timeout_on_RedisManager()
83+
{
84+
var sentinel = new RedisSentinel(new[] { "{0}:{1}".Fmt(TestConfig.SentinelHost, TestConfig.RedisSentinelPort) }, TestConfig.MasterName)
85+
{
86+
RedisManagerFactory = {
87+
OnInit = r => {
88+
((PooledRedisClientManager)r).IdleTimeOutSecs = 20;
89+
}
90+
}
91+
};
92+
93+
using (var clientsManager = (PooledRedisClientManager)sentinel.Setup())
94+
using (var client = clientsManager.GetClient())
95+
{
96+
Assert.That(clientsManager.IdleTimeOutSecs, Is.EqualTo(20));
97+
Assert.That(((RedisNativeClient)client).IdleTimeOutSecs, Is.EqualTo(20));
98+
}
99+
}
81100
}
82101
}

tests/ServiceStack.Redis.Tests/TestConfig.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ static TestConfig()
1313
public const bool IgnoreLongTests = true;
1414

1515
public const string SingleHost = "localhost";
16+
public const string SentinelHost = "10.0.0.9";
1617
public const string MasterName = "mymaster";
1718
public static readonly string[] MasterHosts = new[] { "localhost" };
1819
public static readonly string[] SlaveHosts = new[] { "localhost" };

0 commit comments

Comments
 (0)