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

Commit d262a90

Browse files
committed
Merge pull request #201 from svantreeck/master
updated sentinel parsing and added test on sentinel
2 parents bb9bf59 + 903bd25 commit d262a90

File tree

3 files changed

+90
-100
lines changed

3 files changed

+90
-100
lines changed

src/ServiceStack.Redis/RedisSentinel.cs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,37 @@ public IRedisClientsManager Setup()
5252

5353
private void GetValidSentinel()
5454
{
55-
while (this.clientManager == null && failures < RedisSentinel.MaxFailures)
55+
while (this.clientManager == null && ShouldRetry())
5656
{
5757
try
5858
{
59-
worker = GetNextSentinel();
60-
clientManager = worker.GetClientManager();
61-
worker.BeginListeningForConfigurationChanges();
59+
this.worker = GetNextSentinel();
60+
this.clientManager = worker.GetClientManager();
61+
this.worker.BeginListeningForConfigurationChanges();
6262
}
6363
catch (RedisException)
6464
{
65-
if (worker != null)
65+
if (this.worker != null)
6666
{
67-
worker.SentinelError -= Worker_SentinelError;
68-
worker.Dispose();
67+
this.worker.SentinelError -= Worker_SentinelError;
68+
this.worker.Dispose();
6969
}
7070

71-
failures++;
71+
this.failures++;
7272
}
7373
}
7474
}
7575

76+
/// <summary>
77+
/// Check if GetValidSentinel should try the next sentinel server
78+
/// </summary>
79+
/// <returns></returns>
80+
/// <remarks>This will be true if the failures is less than either RedisSentinel.MaxFailures or the # of sentinels, whatever is greater</remarks>
81+
private bool ShouldRetry()
82+
{
83+
return this.failures < Math.Max(RedisSentinel.MaxFailures, this.sentinels.Count);
84+
}
85+
7686
private RedisSentinelWorker GetNextSentinel()
7787
{
7888
sentinelIndex++;
@@ -88,15 +98,22 @@ private RedisSentinelWorker GetNextSentinel()
8898
return sentinelWorker;
8999
}
90100

101+
/// <summary>
102+
/// Raised if there is an error from a sentinel worker
103+
/// </summary>
104+
/// <param name="sender"></param>
105+
/// <param name="e"></param>
91106
private void Worker_SentinelError(object sender, EventArgs e)
92107
{
93108
var worker = sender as RedisSentinelWorker;
94109

95110
if (worker != null)
96111
{
112+
// dispose the worker
97113
worker.SentinelError -= Worker_SentinelError;
98114
worker.Dispose();
99115

116+
// get a new worker and start looking for more changes
100117
this.worker = GetNextSentinel();
101118
this.worker.BeginListeningForConfigurationChanges();
102119
}

src/ServiceStack.Redis/RedisSentinelWorker.cs

Lines changed: 50 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,38 @@ private void ConfigureRedisFromSentinel()
105105
}
106106
}
107107

108+
private Dictionary<string, string> ParseDataArray(object[] items)
109+
{
110+
Dictionary<string, string> data = new Dictionary<string, string>();
111+
bool isKey = false;
112+
string key = null;
113+
string value = null;
114+
115+
foreach (var item in items)
116+
{
117+
if (item is byte[])
118+
{
119+
isKey = !isKey;
120+
121+
if (isKey)
122+
{
123+
key = Encoding.UTF8.GetString((byte[])item);
124+
}
125+
else
126+
{
127+
value = Encoding.UTF8.GetString((byte[])item);
128+
129+
if (!data.ContainsKey(key))
130+
{
131+
data.Add(key, value);
132+
}
133+
}
134+
}
135+
}
136+
137+
return data;
138+
}
139+
108140
/// <summary>
109141
/// Takes output from sentinel slaves command and converts into a list of servers
110142
/// </summary>
@@ -113,69 +145,26 @@ private void ConfigureRedisFromSentinel()
113145
private IEnumerable<string> ConvertSlaveArrayToList(object[] slaves)
114146
{
115147
var servers = new List<string>();
116-
bool fetchIP = false;
117-
bool fetchPort = false;
118-
bool fetchFlags = false;
119148
string ip = null;
120149
string port = null;
121-
string value = null;
122150
string flags = null;
123151

124152
foreach (var slave in slaves.OfType<object[]>())
125153
{
126-
fetchIP = false;
127-
fetchPort = false;
128-
ip = null;
129-
port = null;
154+
var data = ParseDataArray(slave);
130155

131-
foreach (var item in slave)
132-
{
133-
if (item is byte[])
134-
{
135-
value = Encoding.UTF8.GetString((byte[])item);
136-
if (value == "ip")
137-
{
138-
fetchIP = true;
139-
continue;
140-
}
141-
else if (value == "port")
142-
{
143-
fetchPort = true;
144-
continue;
145-
}
146-
else if (value == "flags")
147-
{
148-
fetchFlags = true;
149-
continue;
150-
}
151-
else if (fetchIP)
152-
{
153-
ip = value;
154-
155-
if (ip == "127.0.0.1")
156-
{
157-
ip = this.sentinelClient.Host;
158-
}
159-
fetchIP = false;
160-
}
161-
else if (fetchPort)
162-
{
163-
port = value;
164-
fetchPort = false;
165-
}
166-
else if (fetchFlags)
167-
{
168-
flags = value;
169-
fetchFlags = false;
170-
171-
if (ip != null && port != null && !flags.Contains("s_down"))
172-
{
173-
servers.Add("{0}:{1}".Fmt(ip, port));
174-
}
175-
}
156+
data.TryGetValue("flags", out flags);
157+
data.TryGetValue("ip", out ip);
158+
data.TryGetValue("port", out port);
176159

160+
if (ip == "127.0.0.1")
161+
{
162+
ip = this.sentinelClient.Host;
163+
}
177164

178-
}
165+
if (ip != null && port != null && !flags.Contains("s_down") && !flags.Contains("o_down"))
166+
{
167+
servers.Add("{0}:{1}".Fmt(ip, port));
179168
}
180169
}
181170

@@ -190,48 +179,17 @@ private IEnumerable<string> ConvertSlaveArrayToList(object[] slaves)
190179
private IEnumerable<string> ConvertMasterArrayToList(object[] items)
191180
{
192181
var servers = new List<string>();
193-
bool fetchIP = false;
194-
bool fetchPort = false;
195182
string ip = null;
196183
string port = null;
197-
string value = null;
198184

199-
foreach (var item in items)
200-
{
201-
if (item is byte[])
202-
{
203-
value = Encoding.UTF8.GetString((byte[])item);
204-
if (value == "ip")
205-
{
206-
fetchIP = true;
207-
continue;
208-
}
209-
else if (value == "port")
210-
{
211-
fetchPort = true;
212-
continue;
213-
}
214-
else if (fetchIP)
215-
{
216-
ip = value;
217-
if (ip == "127.0.0.1")
218-
{
219-
ip = this.sentinelClient.Host;
220-
}
221-
fetchIP = false;
222-
}
223-
else if (fetchPort)
224-
{
225-
port = value;
226-
fetchPort = false;
227-
}
185+
var data = ParseDataArray(items);
228186

229-
if (ip != null && port != null)
230-
{
231-
servers.Add("{0}:{1}".Fmt(ip, port));
232-
break;
233-
}
234-
}
187+
data.TryGetValue("ip", out ip);
188+
data.TryGetValue("port", out port);
189+
190+
if (ip != null && port != null)
191+
{
192+
servers.Add("{0}:{1}".Fmt(ip, port));
235193
}
236194

237195
return servers;

tests/ServiceStack.Redis.Tests/RedisSentinelTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,20 @@ public void Can_Get_Master_Addr()
6363
Assert.AreEqual(host, "127.0.0.1"); // IP of localhost
6464
Assert.AreEqual(port, TestConfig.RedisPort.ToString());
6565
}
66+
67+
[Test]
68+
public void Can_Get_Redis_ClientsManager()
69+
{
70+
var sentinel = new RedisSentinel(new[] { "{0}:{1}".Fmt(TestConfig.SingleHost, TestConfig.RedisSentinelPort) }, TestConfig.MasterName);
71+
72+
var clientsManager = sentinel.Setup();
73+
var client = clientsManager.GetClient();
74+
75+
Assert.AreEqual(client.Host, "127.0.0.1");
76+
Assert.AreEqual(client.Port, TestConfig.RedisPort);
77+
78+
client.Dispose();
79+
sentinel.Dispose();
80+
}
6681
}
6782
}

0 commit comments

Comments
 (0)