Skip to content

Commit 6f22bf5

Browse files
authored
bug: ensure context isn't exhausted via concurrent query
1 parent 8e020c1 commit 6f22bf5

File tree

1 file changed

+40
-18
lines changed

1 file changed

+40
-18
lines changed

sentinel.go

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,6 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
540540
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
541541
return "", err
542542
}
543-
// Continue on other errors
544543
internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName name=%q failed: %s",
545544
c.opt.MasterName, err)
546545
} else {
@@ -558,36 +557,59 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
558557
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
559558
return "", err
560559
}
561-
// Continue on other errors
562560
internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName name=%q failed: %s",
563561
c.opt.MasterName, err)
564562
} else {
565563
return addr, nil
566564
}
567565
}
568566

567+
var (
568+
masterAddr string
569+
wg sync.WaitGroup
570+
once sync.Once
571+
done = make(chan struct{})
572+
)
573+
569574
for i, sentinelAddr := range c.sentinelAddrs {
570-
sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr))
575+
wg.Add(1)
576+
go func(i int, addr string) {
577+
defer wg.Done()
578+
select {
579+
case <-done:
580+
return
581+
default:
582+
sentinelCli := NewSentinelClient(c.opt.sentinelOptions(addr))
583+
addrVal, err := sentinelCli.GetMasterAddrByName(ctx, c.opt.MasterName).Result()
584+
if err != nil {
585+
internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName addr=%s, master=%q failed: %s",
586+
addr, c.opt.MasterName, err)
587+
_ = sentinelCli.Close()
588+
return
589+
}
571590

572-
masterAddr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result()
573-
if err != nil {
574-
_ = sentinel.Close()
575-
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
576-
return "", err
591+
once.Do(func() {
592+
masterAddr = net.JoinHostPort(addrVal[0], addrVal[1])
593+
// Push working sentinel to the top
594+
c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0]
595+
c.setSentinel(ctx, sentinelCli)
596+
internal.Logger.Printf(ctx, "sentinel: selected addr=%s masterAddr=%s", addr, masterAddr)
597+
close(done)
598+
})
577599
}
578-
internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName master=%q failed: %s",
579-
c.opt.MasterName, err)
580-
continue
581-
}
600+
}(i, sentinelAddr)
601+
}
582602

583-
// Push working sentinel to the top.
584-
c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0]
585-
c.setSentinel(ctx, sentinel)
603+
go func() {
604+
wg.Wait()
605+
once.Do(func() { close(done) })
606+
}()
586607

587-
addr := net.JoinHostPort(masterAddr[0], masterAddr[1])
588-
return addr, nil
589-
}
608+
<-done
590609

610+
if masterAddr != "" {
611+
return masterAddr, nil
612+
}
591613
return "", errors.New("redis: all sentinels specified in configuration are unreachable")
592614
}
593615

0 commit comments

Comments
 (0)