@@ -33,7 +33,8 @@ public string MasterName
3333
3434 private int failures = 0 ;
3535 private int sentinelIndex = - 1 ;
36- internal RedisEndpoint [ ] SentinelHosts { get ; private set ; }
36+ public List < string > SentinelHosts { get ; private set ; }
37+ internal RedisEndpoint [ ] SentinelEndpoints { get ; private set ; }
3738 private RedisSentinelWorker worker ;
3839 private static int MaxFailures = 5 ;
3940
@@ -44,30 +45,34 @@ public string MasterName
4445
4546 public Dictionary < string , string > IpAddressMap { get ; set ; }
4647
48+ public bool ScanForOtherSentinels { get ; set ; }
4749 public TimeSpan WaitBetweenSentinelLookups { get ; set ; }
4850 public TimeSpan MaxWaitBetweenSentinelLookups { get ; set ; }
4951 public int SentinelWorkerTimeoutMs { get ; set ; }
5052
5153 public bool ResetWhenSubjectivelyDown { get ; set ; }
5254 public bool ResetWhenObjectivelyDown { get ; set ; }
55+ public bool ResetSentinelsWhenObjectivelyDown { get ; set ; }
5356
5457 public RedisSentinel ( string sentinelHost = null , string masterName = null )
5558 : this ( new [ ] { sentinelHost ?? DefaultAddress } , masterName ?? DefaultMasterName ) { }
5659
5760 public RedisSentinel ( IEnumerable < string > sentinelHosts , string masterName = null )
5861 {
5962 this . SentinelHosts = sentinelHosts != null
60- ? sentinelHosts . Map ( x => x . ToRedisEndpoint ( defaultPort : RedisNativeClient . DefaultPortSentinel ) ) . ToArray ( )
63+ ? sentinelHosts . ToList ( )
6164 : null ;
6265
63- if ( SentinelHosts == null || SentinelHosts . Length == 0 )
66+ if ( SentinelHosts == null || SentinelHosts . Count == 0 )
6467 throw new ArgumentException ( "sentinels must have at least one entry" ) ;
6568
6669 this . masterName = masterName ?? DefaultMasterName ;
6770 IpAddressMap = new Dictionary < string , string > ( ) ;
6871 RedisManagerFactory = ( masters , slaves ) => new PooledRedisClientManager ( masters , slaves ) ;
72+ ScanForOtherSentinels = true ;
6973 ResetWhenObjectivelyDown = true ;
7074 ResetWhenSubjectivelyDown = true ;
75+ ResetSentinelsWhenObjectivelyDown = true ;
7176 SentinelWorkerTimeoutMs = 100 ;
7277 WaitBetweenSentinelLookups = TimeSpan . FromMilliseconds ( 250 ) ;
7378 MaxWaitBetweenSentinelLookups = TimeSpan . FromSeconds ( 60 ) ;
@@ -80,15 +85,69 @@ public IRedisClientsManager Start()
8085 {
8186 lock ( oLock )
8287 {
83- GetValidSentinel ( ) ;
88+ if ( ScanForOtherSentinels )
89+ {
90+ var activeHosts = GetActiveSentinelHosts ( SentinelHosts ) ;
91+ if ( activeHosts . Count == 0 )
92+ throw new ArgumentException ( "Could not find any active sentinels from: " ,
93+ string . Join ( ", " , SentinelHosts . ToArray ( ) ) ) ;
94+
95+ SentinelHosts = activeHosts ;
96+ }
8497
85- if ( this . RedisManager == null )
98+ SentinelEndpoints = SentinelHosts
99+ . Map ( x => x . ToRedisEndpoint ( defaultPort : RedisConfig . DefaultPortSentinel ) )
100+ . ToArray ( ) ;
101+
102+ var sentinelWorker = GetValidSentinelWorker ( ) ;
103+ if ( this . RedisManager == null || sentinelWorker == null )
86104 throw new ApplicationException ( "Unable to resolve sentinels!" ) ;
87105
88106 return this . RedisManager ;
89107 }
90108 }
91109
110+ public List < string > GetActiveSentinelHosts ( IEnumerable < string > sentinelHosts )
111+ {
112+ var activeSentinelHosts = new List < string > ( ) ;
113+ foreach ( var sentinelHost in sentinelHosts . ToArray ( ) )
114+ {
115+ try
116+ {
117+ var endpoint = sentinelHost . ToRedisEndpoint ( defaultPort : RedisConfig . DefaultPortSentinel ) ;
118+ using ( var sentinelWorker = new RedisSentinelWorker ( this , endpoint ) )
119+ {
120+ var activeHosts = sentinelWorker . GetSentinelHosts ( MasterName ) ;
121+
122+ if ( ! activeSentinelHosts . Contains ( sentinelHost ) )
123+ activeSentinelHosts . Add ( sentinelHost ) ;
124+
125+ foreach ( var activeHost in activeHosts )
126+ {
127+ if ( ! activeSentinelHosts . Contains ( activeHost ) )
128+ activeSentinelHosts . Add ( activeHost ) ;
129+ }
130+ }
131+ }
132+ catch ( Exception ex )
133+ {
134+ Log . Error ( "Could not get active Sentinels from: {0}" . Fmt ( sentinelHost ) , ex ) ;
135+ }
136+ }
137+ return activeSentinelHosts ;
138+ }
139+
140+ public void ResetSentinels ( )
141+ {
142+ var activeHosts = GetActiveSentinelHosts ( SentinelHosts ) ;
143+ if ( activeHosts . Count == 0 ) return ;
144+
145+ SentinelHosts = activeHosts ;
146+ SentinelEndpoints = SentinelHosts
147+ . Map ( x => x . ToRedisEndpoint ( defaultPort : RedisConfig . DefaultPortSentinel ) )
148+ . ToArray ( ) ;
149+ }
150+
92151 public Func < string , string > HostFilter { get ; set ; }
93152
94153 internal string [ ] ConfigureHosts ( IEnumerable < string > hosts )
@@ -143,7 +202,7 @@ public IRedisClientsManager GetRedisManager()
143202 return RedisManager ?? ( RedisManager = CreateRedisManager ( GetSentinelInfo ( ) ) ) ;
144203 }
145204
146- private RedisSentinelWorker GetValidSentinel ( )
205+ private RedisSentinelWorker GetValidSentinelWorker ( )
147206 {
148207 if ( this . worker != null )
149208 return this . worker ;
@@ -178,7 +237,7 @@ private RedisSentinelWorker GetValidSentinel()
178237
179238 public RedisEndpoint GetMaster ( )
180239 {
181- var sentinelWorker = GetValidSentinel ( ) ;
240+ var sentinelWorker = GetValidSentinelWorker ( ) ;
182241 lock ( sentinelWorker )
183242 {
184243 var host = sentinelWorker . GetMasterHost ( masterName ) ;
@@ -190,7 +249,7 @@ public RedisEndpoint GetMaster()
190249
191250 public List < RedisEndpoint > GetSlaves ( )
192251 {
193- var sentinelWorker = GetValidSentinel ( ) ;
252+ var sentinelWorker = GetValidSentinelWorker ( ) ;
194253 lock ( sentinelWorker )
195254 {
196255 var hosts = sentinelWorker . GetSlaveHosts ( masterName ) ;
@@ -205,7 +264,7 @@ public List<RedisEndpoint> GetSlaves()
205264 /// <remarks>This will be true if the failures is less than either RedisSentinel.MaxFailures or the # of sentinels, whatever is greater</remarks>
206265 private bool ShouldRetry ( )
207266 {
208- return this . failures < Math . Max ( MaxFailures , this . SentinelHosts . Length ) ;
267+ return this . failures < Math . Max ( MaxFailures , this . SentinelEndpoints . Length ) ;
209268 }
210269
211270 private RedisSentinelWorker GetNextSentinel ( )
@@ -220,10 +279,10 @@ private RedisSentinelWorker GetNextSentinel()
220279 this . worker = null ;
221280 }
222281
223- if ( sentinelIndex >= SentinelHosts . Length )
282+ if ( sentinelIndex >= SentinelEndpoints . Length )
224283 sentinelIndex = 0 ;
225284
226- var sentinelWorker = new RedisSentinelWorker ( this , SentinelHosts [ sentinelIndex ] )
285+ var sentinelWorker = new RedisSentinelWorker ( this , SentinelEndpoints [ sentinelIndex ] )
227286 {
228287 OnSentinelError = OnSentinelError
229288 } ;
@@ -248,7 +307,7 @@ private void OnSentinelError(Exception ex)
248307
249308 public SentinelInfo GetSentinelInfo ( )
250309 {
251- var sentinelWorker = GetValidSentinel ( ) ;
310+ var sentinelWorker = GetValidSentinelWorker ( ) ;
252311 lock ( sentinelWorker )
253312 {
254313 return sentinelWorker . GetSentinelInfo ( ) ;
0 commit comments