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

Commit 48c47c5

Browse files
committed
Add proper impl RedisSentinelResolver always check Sentinels for hosts, only use cache as fallback
1 parent e549a50 commit 48c47c5

2 files changed

Lines changed: 79 additions & 48 deletions

File tree

src/ServiceStack.Redis/BasicRedisClientManager.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,17 @@ public BasicRedisClientManager(int initialDb, params string[] readWriteHosts)
6262
/// </summary>
6363
/// <param name="readWriteHosts">The write hosts.</param>
6464
/// <param name="readOnlyHosts">The read hosts.</param>
65+
/// <param name="initalDb"></param>
6566
public BasicRedisClientManager(
6667
IEnumerable<string> readWriteHosts,
67-
IEnumerable<string> readOnlyHosts)
68-
: this(readWriteHosts, readOnlyHosts, null) {}
68+
IEnumerable<string> readOnlyHosts,
69+
long? initalDb = null)
70+
: this(readWriteHosts.ToRedisEndPoints(), readOnlyHosts.ToRedisEndPoints(), initalDb) {}
6971

7072
public BasicRedisClientManager(
71-
IEnumerable<string> readWriteHosts,
72-
IEnumerable<string> readOnlyHosts,
73-
long? initalDb)
73+
IEnumerable<RedisEndpoint> readWriteHosts,
74+
IEnumerable<RedisEndpoint> readOnlyHosts,
75+
long? initalDb = null)
7476
{
7577
this.Db = initalDb;
7678

src/ServiceStack.Redis/RedisSentinelResolver.cs

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Linq;
5+
using System.Threading;
46
using ServiceStack.Logging;
57

68
namespace ServiceStack.Redis
@@ -74,68 +76,95 @@ public virtual void ResetSlaves(List<RedisEndpoint> newSlaves)
7476
log.Debug("New Redis Slaves: " + string.Join(", ", slaves.Map(x => x.GetHostString())));
7577
}
7678

79+
public RedisEndpoint GetReadWriteHost(int desiredIndex)
80+
{
81+
return sentinel.GetMaster() ?? masters[desiredIndex % masters.Length];
82+
}
83+
84+
public RedisEndpoint GetReadOnlyHost(int desiredIndex)
85+
{
86+
var slavesEndpoints = sentinel.GetSlaves();
87+
if (slavesEndpoints.Count > 0)
88+
return slavesEndpoints[desiredIndex % slavesEndpoints.Count];
89+
90+
return ReadOnlyHostsCount > 0
91+
? slaves[desiredIndex % slaves.Length]
92+
: GetReadWriteHost(desiredIndex);
93+
}
94+
7795
public virtual RedisClient CreateRedisClient(RedisEndpoint config, bool readWrite)
7896
{
7997
var client = RedisConfig.ClientFactory(config);
8098

81-
if (readWrite && RedisConfig.VerifyMasterConnections)
99+
if (readWrite)
82100
{
83101
var role = client.GetServerRole();
84102
if (role != RedisServerRole.Master)
85103
{
86-
log.Error("Redis Master Host '{0}' is {1}. Resetting allHosts...".Fmt(config.GetHostString(), role));
87-
var newMasters = new List<RedisEndpoint>();
88-
var newSlaves = new List<RedisEndpoint>();
89-
RedisClient masterClient = null;
90-
foreach (var hostConfig in allHosts)
104+
try
105+
{
106+
var stopwatch = Stopwatch.StartNew();
107+
while (true)
108+
{
109+
var masterConfig = sentinel.GetMaster();
110+
var master = RedisConfig.ClientFactory(masterConfig);
111+
var masterRole = master.GetServerRole();
112+
if (masterRole == RedisServerRole.Master)
113+
return master;
114+
115+
if (stopwatch.Elapsed > sentinel.MaxWaitBetweenSentinelLookups)
116+
throw new TimeoutException("Max Wait Between Sentinel Lookups Elapsed: {0}"
117+
.Fmt(sentinel.MaxWaitBetweenSentinelLookups.ToString()));
118+
119+
Thread.Sleep(sentinel.WaitBetweenSentinelLookups);
120+
}
121+
}
122+
catch (Exception ex)
91123
{
92-
try
124+
log.Error("Redis Master Host '{0}' is {1}. Resetting allHosts...".Fmt(config.GetHostString(), role), ex);
125+
var newMasters = new List<RedisEndpoint>();
126+
var newSlaves = new List<RedisEndpoint>();
127+
RedisClient masterClient = null;
128+
foreach (var hostConfig in allHosts)
93129
{
94-
var testClient = new RedisClient(hostConfig) {
95-
ConnectTimeout = RedisConfig.SentinelConnectTimeout
96-
};
97-
var testRole = testClient.GetServerRole();
98-
switch (testRole)
130+
try
99131
{
100-
case RedisServerRole.Master:
101-
newMasters.Add(hostConfig);
102-
if (masterClient == null)
103-
masterClient = testClient;
104-
break;
105-
case RedisServerRole.Slave:
106-
newSlaves.Add(hostConfig);
107-
break;
132+
var testClient = new RedisClient(hostConfig)
133+
{
134+
ConnectTimeout = RedisConfig.HostLookupTimeout
135+
};
136+
var testRole = testClient.GetServerRole();
137+
switch (testRole)
138+
{
139+
case RedisServerRole.Master:
140+
newMasters.Add(hostConfig);
141+
if (masterClient == null)
142+
masterClient = testClient;
143+
break;
144+
case RedisServerRole.Slave:
145+
newSlaves.Add(hostConfig);
146+
break;
147+
}
148+
108149
}
150+
catch { /* skip */ }
151+
}
109152

153+
if (masterClient == null)
154+
{
155+
var errorMsg = "No master found in: " + string.Join(", ", allHosts.Map(x => x.GetHostString()));
156+
log.Error(errorMsg);
157+
throw new Exception(errorMsg);
110158
}
111-
catch { /* skip */ }
112-
}
113159

114-
if (masterClient == null)
115-
{
116-
var errorMsg = "No master found in: " + string.Join(", ", allHosts.Map(x => x.GetHostString()));
117-
log.Error(errorMsg);
118-
throw new Exception(errorMsg);
160+
ResetMasters(newMasters);
161+
ResetSlaves(newSlaves);
162+
return masterClient;
119163
}
120-
121-
ResetMasters(newMasters);
122-
ResetSlaves(newSlaves);
123-
return masterClient;
124164
}
125165
}
126166

127167
return client;
128168
}
129-
130-
public RedisEndpoint GetReadWriteHost(int desiredIndex)
131-
{
132-
return masters[desiredIndex % masters.Length];
133-
}
134-
135-
public RedisEndpoint GetReadOnlyHost(int desiredIndex)
136-
{
137-
return ReadOnlyHostsCount > 0
138-
? slaves[desiredIndex % slaves.Length]
139-
: GetReadWriteHost(desiredIndex);
140-
} }
169+
}
141170
}

0 commit comments

Comments
 (0)