From 7e63d6519af80292500b8f8105e90af7867308f7 Mon Sep 17 00:00:00 2001 From: kwen <38367518+kwenzh@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:26:39 +0800 Subject: [PATCH] bug: fix Query sentinel changed to concurrent query to avoid context exhaustion --- sentinel.go | 54 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/sentinel.go b/sentinel.go index 31569554..46ab755e 100644 --- a/sentinel.go +++ b/sentinel.go @@ -549,26 +549,50 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) { } } + var masterAddr string + var wg sync.WaitGroup + var once sync.Once + done := make(chan struct{}) + for i, sentinelAddr := range c.sentinelAddrs { - sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr)) + wg.Add(1) + go func(i int, addr string) { + defer wg.Done() + select { + case <-done: + default: + sentinelCli := NewSentinelClient(c.opt.sentinelOptions(addr)) + addrVal, err := sentinelCli.GetMasterAddrByName(ctx, c.opt.MasterName).Result() + if err != nil { + internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName addr=%s, master=%q failed: %s", + addr, c.opt.MasterName, err) + _ = sentinelCli.Close() + return + } + internal.Logger.Printf(ctx, "get addr %s master res %v", addr, masterAddr) + once.Do(func() { + // Push working sentinel to the top. + masterAddr = net.JoinHostPort(addrVal[0], addrVal[1]) + c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0] + c.setSentinel(ctx, sentinelCli) + close(done) + + }) - masterAddr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result() - if err != nil { - _ = sentinel.Close() - if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { - return "", err } - internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName master=%q failed: %s", - c.opt.MasterName, err) - continue - } - // Push working sentinel to the top. - c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0] - c.setSentinel(ctx, sentinel) + }(i, sentinelAddr) - addr := net.JoinHostPort(masterAddr[0], masterAddr[1]) - return addr, nil + } + go func() { + wg.Wait() + once.Do(func() { + close(done) + }) + }() + <-done + if masterAddr != "" { + return masterAddr, nil } return "", errors.New("redis: all sentinels specified in configuration are unreachable")