[#1456] services/tree: Wait some time before reconnecting after failure

In case node is down or failing for some reason, we can expect `Dial` to
fail. In case we actively try to replicate and `Dial` always takes 2
seconds, replication-related channels quickly become full. That affects
latency of all other write operations.

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2022-06-06 14:46:00 +03:00 committed by fyrchik
parent 39f47f61c6
commit 5ffbeb76e6

View file

@ -2,6 +2,7 @@ package tree
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -17,9 +18,15 @@ type clientCache struct {
simplelru.LRU simplelru.LRU
} }
type cacheItem struct {
cc *grpc.ClientConn
lastTry time.Time
}
const ( const (
defaultClientCacheSize = 10 defaultClientCacheSize = 10
defaultClientConnectTimeout = time.Second * 2 defaultClientConnectTimeout = time.Second * 2
defaultReconnectInterval = time.Second * 15
) )
func (c *clientCache) init() { func (c *clientCache) init() {
@ -35,22 +42,35 @@ func (c *clientCache) get(ctx context.Context, netmapAddr string) (TreeServiceCl
c.Unlock() c.Unlock()
if ok { if ok {
cc := ccInt.(*grpc.ClientConn) item := ccInt.(cacheItem)
if s := cc.GetState(); s == connectivity.Idle || s == connectivity.Ready { if item.cc == nil {
return NewTreeServiceClient(cc), nil if d := time.Since(item.lastTry); d < defaultReconnectInterval {
return nil, fmt.Errorf("skip connecting to %s (time since last error %s)",
netmapAddr, d)
}
} else {
if s := item.cc.GetState(); s == connectivity.Idle || s == connectivity.Ready {
return NewTreeServiceClient(item.cc), nil
}
_ = item.cc.Close()
} }
_ = cc.Close()
} }
cc, err := dialTreeService(ctx, netmapAddr) cc, err := dialTreeService(ctx, netmapAddr)
lastTry := time.Now()
c.Lock()
if err != nil {
c.LRU.Add(netmapAddr, cacheItem{cc: nil, lastTry: lastTry})
} else {
c.LRU.Add(netmapAddr, cacheItem{cc: cc, lastTry: lastTry})
}
c.Unlock()
if err != nil { if err != nil {
return nil, err return nil, err
} }
c.Lock()
c.LRU.Add(netmapAddr, cc)
c.Unlock()
return NewTreeServiceClient(cc), nil return NewTreeServiceClient(cc), nil
} }