@@ -36,6 +36,12 @@ type FailoverOptions struct {
36
36
// Route all commands to slave read-only nodes.
37
37
SlaveOnly bool
38
38
39
+ // Use slaves disconnected with master when cannot get connected slaves
40
+ // Now, this option only works in RandomSlaveAddr function.
41
+ UseDisconnectedSlaves bool
42
+
43
+ // Client queries sentinels in a random order
44
+ QuerySentinelRandomly bool
39
45
// Following options are copied from Options struct.
40
46
41
47
Dialer func (ctx context.Context , network , addr string ) (net.Conn , error )
@@ -433,10 +439,22 @@ func (c *sentinelFailover) closeSentinel() error {
433
439
}
434
440
435
441
func (c * sentinelFailover ) RandomSlaveAddr (ctx context.Context ) (string , error ) {
436
- addresses , err := c .slaveAddrs (ctx )
442
+ if c .opt == nil {
443
+ return "" , errors .New ("opt is nil" )
444
+ }
445
+
446
+ addresses , err := c .slaveAddrs (ctx , false )
437
447
if err != nil {
438
448
return "" , err
439
449
}
450
+
451
+ if len (addresses ) == 0 && c .opt .UseDisconnectedSlaves {
452
+ addresses , err = c .slaveAddrs (ctx , true )
453
+ if err != nil {
454
+ return "" , err
455
+ }
456
+ }
457
+
440
458
if len (addresses ) == 0 {
441
459
return c .MasterAddr (ctx )
442
460
}
@@ -466,6 +484,11 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
466
484
_ = c .closeSentinel ()
467
485
}
468
486
487
+ if c .opt .QuerySentinelRandomly {
488
+ rand .Shuffle (len (c .sentinelAddrs ), func (i , j int ) {
489
+ c .sentinelAddrs [i ], c .sentinelAddrs [j ] = c .sentinelAddrs [j ], c .sentinelAddrs [i ]
490
+ })
491
+ }
469
492
for i , sentinelAddr := range c .sentinelAddrs {
470
493
sentinel := NewSentinelClient (c .opt .sentinelOptions (sentinelAddr ))
471
494
@@ -488,7 +511,7 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
488
511
return "" , errors .New ("redis: all sentinels specified in configuration are unreachable" )
489
512
}
490
513
491
- func (c * sentinelFailover ) slaveAddrs (ctx context.Context ) ([]string , error ) {
514
+ func (c * sentinelFailover ) slaveAddrs (ctx context.Context , useDisconnected bool ) ([]string , error ) {
492
515
c .mu .RLock ()
493
516
sentinel := c .sentinel
494
517
c .mu .RUnlock ()
@@ -510,6 +533,13 @@ func (c *sentinelFailover) slaveAddrs(ctx context.Context) ([]string, error) {
510
533
}
511
534
_ = c .closeSentinel ()
512
535
}
536
+ if c .opt .QuerySentinelRandomly {
537
+ rand .Shuffle (len (c .sentinelAddrs ), func (i , j int ) {
538
+ c .sentinelAddrs [i ], c .sentinelAddrs [j ] = c .sentinelAddrs [j ], c .sentinelAddrs [i ]
539
+ })
540
+ }
541
+
542
+ var sentinelReachable bool
513
543
514
544
for i , sentinelAddr := range c .sentinelAddrs {
515
545
sentinel := NewSentinelClient (c .opt .sentinelOptions (sentinelAddr ))
@@ -521,15 +551,21 @@ func (c *sentinelFailover) slaveAddrs(ctx context.Context) ([]string, error) {
521
551
_ = sentinel .Close ()
522
552
continue
523
553
}
524
-
554
+ sentinelReachable = true
555
+ addrs := parseSlaveAddrs (slaves , useDisconnected )
556
+ if len (addrs ) == 0 {
557
+ continue
558
+ }
525
559
// Push working sentinel to the top.
526
560
c .sentinelAddrs [0 ], c .sentinelAddrs [i ] = c .sentinelAddrs [i ], c .sentinelAddrs [0 ]
527
561
c .setSentinel (ctx , sentinel )
528
562
529
- addrs := parseSlaveAddrs (slaves )
530
563
return addrs , nil
531
564
}
532
565
566
+ if sentinelReachable {
567
+ return []string {}, nil
568
+ }
533
569
return []string {}, errors .New ("redis: all sentinels specified in configuration are unreachable" )
534
570
}
535
571
@@ -550,12 +586,11 @@ func (c *sentinelFailover) getSlaveAddrs(ctx context.Context, sentinel *Sentinel
550
586
c .opt .MasterName , err )
551
587
return []string {}
552
588
}
553
- return parseSlaveAddrs (addrs )
589
+ return parseSlaveAddrs (addrs , false )
554
590
}
555
591
556
- func parseSlaveAddrs (addrs []interface {}) []string {
592
+ func parseSlaveAddrs (addrs []interface {}, keepDisconnected bool ) []string {
557
593
nodes := make ([]string , 0 , len (addrs ))
558
-
559
594
for _ , node := range addrs {
560
595
ip := ""
561
596
port := ""
@@ -577,8 +612,12 @@ func parseSlaveAddrs(addrs []interface{}) []string {
577
612
578
613
for _ , flag := range flags {
579
614
switch flag {
580
- case "s_down" , "o_down" , "disconnected" :
615
+ case "s_down" , "o_down" :
581
616
isDown = true
617
+ case "disconnected" :
618
+ if ! keepDisconnected {
619
+ isDown = true
620
+ }
582
621
}
583
622
}
584
623
@@ -705,7 +744,7 @@ func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient {
705
744
Addr : masterAddr ,
706
745
}}
707
746
708
- slaveAddrs , err := failover .slaveAddrs (ctx )
747
+ slaveAddrs , err := failover .slaveAddrs (ctx , false )
709
748
if err != nil {
710
749
return nil , err
711
750
}
0 commit comments