From 56953a596209fd6dccb2e1ae77ef9a55b35ce280 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Thu, 4 Apr 2024 23:37:28 +0000 Subject: [PATCH] server: Retry seeder connections If all seeders are unreachable (e.g. the network is not up yet, or DNS lookups are failing) and the address manager is flagged as needing more addresses, continue to try and reach the seeders in additional background goroutines with an increasing backoff timeout. --- server.go | 77 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/server.go b/server.go index 5715a2b1df..5286e4855a 100644 --- a/server.go +++ b/server.go @@ -3096,36 +3096,59 @@ func (s *server) rebroadcastHandler(ctx context.Context) { func (s *server) querySeeders(ctx context.Context) { // Add peers discovered through DNS to the address manager. seeders := s.chainParams.Seeders() - for _, seeder := range seeders { - go func(seeder string) { - ctx, cancel := context.WithTimeout(ctx, time.Minute) - defer cancel() + errs := make(chan error, len(seeders)) + seed := func(seeder string) { + ctx, cancel := context.WithTimeout(ctx, time.Minute) + defer cancel() - addrs, err := connmgr.SeedAddrs(ctx, seeder, dcrdDial, - connmgr.SeedFilterServices(defaultRequiredServices)) - if err != nil { - srvrLog.Infof("seeder '%s' error: %v", seeder, err) - return - } + addrs, err := connmgr.SeedAddrs(ctx, seeder, dcrdDial, + connmgr.SeedFilterServices(defaultRequiredServices)) + if err != nil { + srvrLog.Infof("seeder '%s' error: %v", seeder, err) + errs <- err + return + } - // Nothing to do if the seeder didn't return any addresses. - if len(addrs) == 0 { - return - } + // Nothing to do if the seeder didn't return any addresses. + if len(addrs) == 0 { + errs <- nil + return + } - // Lookup the IP of the https seeder to use as the source of the - // seeded addresses. In the incredibly rare event that the lookup - // fails after it just succeeded, fall back to using the first - // returned address as the source. - srcAddr := wireToAddrmgrNetAddress(addrs[0]) - srcIPs, err := dcrdLookup(seeder) - if err == nil && len(srcIPs) > 0 { - const httpsPort = 443 - srcAddr = addrmgr.NewNetAddressIPPort(srcIPs[0], httpsPort, 0) + // Lookup the IP of the https seeder to use as the source of the + // seeded addresses. In the incredibly rare event that the lookup + // fails after it just succeeded, fall back to using the first + // returned address as the source. + srcAddr := wireToAddrmgrNetAddress(addrs[0]) + srcIPs, err := dcrdLookup(seeder) + if err == nil && len(srcIPs) > 0 { + const httpsPort = 443 + srcAddr = addrmgr.NewNetAddressIPPort(srcIPs[0], httpsPort, 0) + } + addresses := wireToAddrmgrNetAddresses(addrs) + s.addrManager.AddAddresses(addresses, srcAddr) + errs <- nil + } + + backoff := time.Second + for { + for _, seeder := range seeders { + go seed(seeder) + } + var errCount int + for range seeders { + if err := <-errs; err != nil { + errCount++ } - addresses := wireToAddrmgrNetAddresses(addrs) - s.addrManager.AddAddresses(addresses, srcAddr) - }(seeder) + } + if errCount < len(seeders) || !s.addrManager.NeedMoreAddresses() { + return + } + + time.Sleep(backoff) + if backoff < 10*time.Second { + backoff += time.Second + } } } @@ -3153,7 +3176,7 @@ func (s *server) Run(ctx context.Context) { wg.Add(1) go func() { if !cfg.DisableSeeders { - s.querySeeders(ctx) + go s.querySeeders(ctx) } s.connManager.Run(ctx) wg.Done()