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

Commit 93e2522

Browse files
committed
Add typed Sentinel commands
1 parent 1d9acf5 commit 93e2522

File tree

3 files changed

+175
-94
lines changed

3 files changed

+175
-94
lines changed

src/ServiceStack.Redis/Commands.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,5 +205,9 @@ public static class Commands
205205

206206
// Sentinel commands
207207
public readonly static byte[] Sentinel = "SENTINEL".ToUtf8Bytes();
208+
public readonly static byte[] Masters = "masters".ToUtf8Bytes();
209+
public readonly static byte[] Master = "master".ToUtf8Bytes();
210+
public readonly static byte[] Slaves = "slaves".ToUtf8Bytes();
211+
public readonly static byte[] GetMasterAddrByName = "get-master-addr-by-name".ToUtf8Bytes();
208212
}
209213
}

src/ServiceStack.Redis/RedisNativeClient.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,78 @@ public byte[] BRPopLPush(string fromListId, string toListId, int timeOutSecs)
14471447

14481448
#endregion
14491449

1450+
#region Sentinel
1451+
1452+
private static Dictionary<string, string> ToDictionary(object[] result)
1453+
{
1454+
var masterInfo = new Dictionary<string, string>();
1455+
1456+
string key = null;
1457+
for (var i = 0; i < result.Length; i++)
1458+
{
1459+
var bytes = (byte[])result[i];
1460+
if (i % 2 == 0)
1461+
{
1462+
key = bytes.FromUtf8Bytes();
1463+
}
1464+
else
1465+
{
1466+
var val = bytes.FromUtf8Bytes();
1467+
masterInfo[key] = val;
1468+
}
1469+
}
1470+
return masterInfo;
1471+
}
1472+
1473+
public List<Dictionary<string, string>> SentinelMasters()
1474+
{
1475+
var args = new List<byte[]>
1476+
{
1477+
Commands.Sentinel,
1478+
Commands.Masters,
1479+
};
1480+
var results = SendExpectDeeplyNestedMultiData(args.ToArray());
1481+
return (from object[] result in results select ToDictionary(result)).ToList();
1482+
}
1483+
1484+
public Dictionary<string, string> SentinelMaster(string masterName)
1485+
{
1486+
var args = new List<byte[]>
1487+
{
1488+
Commands.Sentinel,
1489+
Commands.Master,
1490+
masterName.ToUtf8Bytes(),
1491+
};
1492+
var results = SendExpectDeeplyNestedMultiData(args.ToArray());
1493+
return ToDictionary(results);
1494+
}
1495+
1496+
public List<Dictionary<string, string>> SentinelSlaves(string masterName)
1497+
{
1498+
var args = new List<byte[]>
1499+
{
1500+
Commands.Sentinel,
1501+
Commands.Slaves,
1502+
masterName.ToUtf8Bytes(),
1503+
};
1504+
var results = SendExpectDeeplyNestedMultiData(args.ToArray());
1505+
return (from object[] result in results select ToDictionary(result)).ToList();
1506+
}
1507+
1508+
public List<string> SentinelGetMasterAddrByName(string masterName)
1509+
{
1510+
var args = new List<byte[]>
1511+
{
1512+
Commands.Sentinel,
1513+
Commands.GetMasterAddrByName,
1514+
masterName.ToUtf8Bytes(),
1515+
};
1516+
1517+
return SendExpectMultiData(args.ToArray()).ToStringList();
1518+
}
1519+
1520+
#endregion
1521+
14501522
#region Sorted Set Operations
14511523

14521524
private static void AssertSetIdAndValue(string setId, byte[] value)

tests/ServiceStack.Redis.Tests/RedisSentinelTests.cs

Lines changed: 99 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
3-
using System.Text;
44
using System.Threading;
55
using NUnit.Framework;
66
using ServiceStack.Logging;
@@ -9,30 +9,40 @@
99

1010
namespace ServiceStack.Redis.Tests
1111
{
12-
[Ignore("Reenable when CI has Sentinel")]
12+
//[Ignore("Reenable when CI has Sentinel")]
1313
[TestFixture, Category("Integration")]
1414
public class RedisSentinelTests
15-
: RedisClientTestsBase
15+
: RedisSentinelTestBase
1616
{
17-
protected RedisClient RedisSentinel;
18-
19-
20-
public override void OnBeforeEachTest()
17+
[TestFixtureSetUp]
18+
public void OnBeforeTestFixture()
2119
{
22-
base.OnBeforeEachTest();
20+
StartAllRedisServers();
21+
StartAllRedisSentinels();
22+
}
2323

24-
RedisSentinel = new RedisClient(TestConfig.SentinelHost, TestConfig.RedisSentinelPort);
24+
[TestFixtureTearDown]
25+
public void OnAfterTestFixture()
26+
{
27+
ShutdownAllRedisSentinels();
28+
ShutdownAllRedisServers();
2529
}
2630

31+
protected RedisClient RedisSentinel;
2732

28-
public override void TearDown()
33+
[SetUp]
34+
public void OnBeforeEachTest()
2935
{
30-
base.TearDown();
36+
var parts = SentinelHosts[0].SplitOnFirst(':');
37+
RedisSentinel = new RedisClient(parts[0], int.Parse(parts[1]));
38+
}
3139

40+
[TearDown]
41+
public void OnAfterEachTest()
42+
{
3243
RedisSentinel.Dispose();
3344
}
3445

35-
3646
[Test]
3747
public void Can_Ping_Sentinel()
3848
{
@@ -42,134 +52,129 @@ public void Can_Ping_Sentinel()
4252
[Test]
4353
public void Can_Get_Sentinel_Masters()
4454
{
45-
object[] masters = RedisSentinel.Sentinel("masters");
55+
var masters = RedisSentinel.SentinelMasters();
56+
masters.PrintDump();
57+
58+
Assert.That(masters.Count, Is.GreaterThan(0));
59+
}
60+
61+
[Test]
62+
public void Can_Get_Sentinel_Master()
63+
{
64+
var master = RedisSentinel.SentinelMaster(MasterName);
65+
master.PrintDump();
4666

47-
Assert.AreEqual(masters.Count(), TestConfig.MasterHosts.Count());
67+
var host = "{0}:{1}".Fmt(master["ip"], master["port"]);
68+
Assert.That(master["name"], Is.EqualTo(MasterName));
69+
Assert.That(host, Is.EqualTo(MasterHosts[0]));
4870
}
4971

5072
[Test]
5173
public void Can_Get_Sentinel_Slaves()
5274
{
53-
object[] slaves = RedisSentinel.Sentinel("slaves", TestConfig.MasterName);
75+
var slaves = RedisSentinel.SentinelSlaves(MasterName);
76+
slaves.PrintDump();
5477

55-
Assert.That(slaves.Count(), Is.GreaterThan(0));
78+
Assert.That(slaves.Count, Is.GreaterThan(0));
5679
}
5780

5881
[Test]
5982
public void Can_Get_Master_Addr()
6083
{
61-
object[] addr = RedisSentinel.Sentinel("get-master-addr-by-name", TestConfig.MasterName);
84+
var addr = RedisSentinel.SentinelGetMasterAddrByName(MasterName);
6285

63-
string host = Encoding.UTF8.GetString((byte[])addr[0]);
64-
string port = Encoding.UTF8.GetString((byte[])addr[1]);
86+
string host = addr[0];
87+
string port = addr[1];
88+
var hostString = "{0}:{1}".Fmt(host, port);
6589

6690
// IP of localhost
67-
Assert.That(host, Is.EqualTo("127.0.0.1").Or.EqualTo(TestConfig.SentinelHost));
68-
Assert.AreEqual(port, TestConfig.RedisPort.ToString());
91+
Assert.That(hostString, Is.EqualTo(MasterHosts[0]));
6992
}
7093

7194
[Test]
7295
public void Can_Get_Redis_ClientsManager()
7396
{
74-
var sentinel = new RedisSentinel(new[] { "{0}:{1}".Fmt(TestConfig.SentinelHost, TestConfig.RedisSentinelPort) }, TestConfig.MasterName);
75-
76-
var clientsManager = sentinel.Start();
77-
var client = clientsManager.GetClient();
78-
79-
Assert.That(client.Host, Is.EqualTo("127.0.0.1").Or.EqualTo(TestConfig.SentinelHost));
80-
Assert.AreEqual(client.Port, TestConfig.RedisPort);
81-
82-
client.Dispose();
83-
sentinel.Dispose();
97+
using (var sentinel = CreateSentinel())
98+
{
99+
var clientsManager = sentinel.Start();
100+
using (var client = clientsManager.GetClient())
101+
{
102+
Assert.That(client.GetHostString(), Is.EqualTo(MasterHosts[0]));
103+
}
104+
}
84105
}
85106

86107
[Test]
87108
public void Can_specify_Timeout_on_RedisManager()
88109
{
89-
var sentinel = new RedisSentinel(new[] { "{0}:{1}".Fmt(TestConfig.SentinelHost, TestConfig.RedisSentinelPort) }, TestConfig.MasterName)
110+
using (var sentinel = CreateSentinel())
90111
{
91-
RedisManagerFactory =
112+
sentinel.RedisManagerFactory = (masters, slaves) => new PooledRedisClientManager(masters, slaves) { IdleTimeOutSecs = 20 };
113+
114+
using (var clientsManager = (PooledRedisClientManager)sentinel.Start())
115+
using (var client = clientsManager.GetClient())
92116
{
93-
OnInit = r =>
94-
{
95-
((PooledRedisClientManager)r).IdleTimeOutSecs = 20;
96-
}
117+
Assert.That(clientsManager.IdleTimeOutSecs, Is.EqualTo(20));
118+
Assert.That(((RedisNativeClient)client).IdleTimeOutSecs, Is.EqualTo(20));
97119
}
98-
};
99-
100-
using (var clientsManager = (PooledRedisClientManager)sentinel.Start())
101-
using (var client = clientsManager.GetClient())
102-
{
103-
Assert.That(clientsManager.IdleTimeOutSecs, Is.EqualTo(20));
104-
Assert.That(((RedisNativeClient)client).IdleTimeOutSecs, Is.EqualTo(20));
105120
}
106121
}
107122

108123
[Test]
109124
public void Can_specify_db_on_RedisSentinel()
110125
{
111-
var sentinelHosts = new[] { "{0}:{1}".Fmt(TestConfig.SentinelHost, TestConfig.RedisSentinelPort) };
112-
var sentinel = new RedisSentinel(sentinelHosts, TestConfig.MasterName)
126+
using (var sentinel = CreateSentinel())
113127
{
114-
HostFilter = host => "{0}?db=1".Fmt(host)
115-
};
116-
117-
using (var clientsManager = sentinel.Start())
118-
using (var client = clientsManager.GetClient())
119-
{
120-
Assert.That(client.Db, Is.EqualTo(1));
128+
sentinel.HostFilter = host => "{0}?db=1".Fmt(host);
129+
130+
using (var clientsManager = sentinel.Start())
131+
using (var client = clientsManager.GetClient())
132+
{
133+
Assert.That(client.Db, Is.EqualTo(1));
134+
}
121135
}
122136
}
123137

124-
[Test]
138+
[Ignore,Test]
125139
public void Run_sentinel_for_10_minutes()
126140
{
127141
LogManager.LogFactory = new ConsoleLogFactory(debugEnabled: true);
128142

129-
var sentinelHost = "{0}:{1}".Fmt(TestConfig.SentinelHost, TestConfig.RedisSentinelPort);
130-
var sentinel = new RedisSentinel(sentinelHost, TestConfig.MasterName)
143+
using (var sentinel = CreateSentinel())
131144
{
132-
OnFailover = manager =>
133-
{
134-
"Redis Managers Failed Over to new hosts".Print();
135-
},
136-
OnWorkerError = ex =>
137-
{
138-
"Worker error: {0}".Print(ex);
139-
},
140-
OnSentinelMessageReceived = (channel, msg) =>
141-
{
142-
"Received '{0}' on channel '{1}' from Sentinel".Print(channel, msg);
143-
},
144-
};
145+
sentinel.OnFailover = manager => "Redis Managers Failed Over to new hosts".Print();
146+
sentinel.OnWorkerError = ex => "Worker error: {0}".Print(ex);
147+
sentinel.OnSentinelMessageReceived = (channel, msg) => "Received '{0}' on channel '{1}' from Sentinel".Print(channel, msg);
145148

146-
var redisManager = sentinel.Start();
147-
148-
var aTimer = new Timer
149-
{
150-
Interval = 1000,
151-
Enabled = true
152-
};
153-
aTimer.Elapsed += (sender, args) =>
154-
{
155-
"Incrementing key".Print();
156-
157-
string key = null;
158-
using (var redis = redisManager.GetClient())
159-
{
160-
var counter = redis.Increment("key", 1);
161-
key = "key" + counter;
162-
"Set key {0} in read/write client".Print(key);
163-
redis.SetEntry(key, "value" + 1);
164-
}
165-
166-
using (var redis = redisManager.GetClient())
149+
using (var redisManager = sentinel.Start())
167150
{
168-
"Get key {0} in read-only client...".Print(key);
169-
var value = redis.GetEntry(key);
170-
"{0} = {1}".Print(key, value);
151+
var aTimer = new Timer
152+
{
153+
Interval = 1000,
154+
Enabled = true
155+
};
156+
aTimer.Elapsed += (sender, args) =>
157+
{
158+
"Incrementing key".Print();
159+
160+
string key = null;
161+
using (var redis = redisManager.GetClient())
162+
{
163+
var counter = redis.Increment("key", 1);
164+
key = "key" + counter;
165+
"Set key {0} in read/write client".Print(key);
166+
redis.SetEntry(key, "value" + 1);
167+
}
168+
169+
using (var redis = redisManager.GetClient())
170+
{
171+
"Get key {0} in read-only client...".Print(key);
172+
var value = redis.GetEntry(key);
173+
"{0} = {1}".Print(key, value);
174+
}
175+
};
171176
}
172-
};
177+
}
173178

174179
Thread.Sleep(TimeSpan.FromMinutes(10));
175180
}

0 commit comments

Comments
 (0)