github.com/thanos-io/thanos@v0.32.5/pkg/discovery/memcache/provider.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package memcache
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/go-kit/log"
    13  	"github.com/go-kit/log/level"
    14  	"github.com/prometheus/client_golang/prometheus"
    15  	"github.com/prometheus/client_golang/prometheus/promauto"
    16  
    17  	"github.com/thanos-io/thanos/pkg/errutil"
    18  	"github.com/thanos-io/thanos/pkg/extprom"
    19  )
    20  
    21  // Provider is a stateful cache for asynchronous memcached auto-discovery resolution. It provides a way to resolve
    22  // addresses and obtain them.
    23  type Provider struct {
    24  	sync.RWMutex
    25  	resolver       Resolver
    26  	clusterConfigs map[string]*clusterConfig
    27  	logger         log.Logger
    28  
    29  	configVersion         *extprom.TxGaugeVec
    30  	resolvedAddresses     *extprom.TxGaugeVec
    31  	resolverFailuresCount prometheus.Counter
    32  	resolverLookupsCount  prometheus.Counter
    33  }
    34  
    35  func NewProvider(logger log.Logger, reg prometheus.Registerer, dialTimeout time.Duration) *Provider {
    36  	p := &Provider{
    37  		resolver:       &memcachedAutoDiscovery{dialTimeout: dialTimeout},
    38  		clusterConfigs: map[string]*clusterConfig{},
    39  		configVersion: extprom.NewTxGaugeVec(reg, prometheus.GaugeOpts{
    40  			Name: "auto_discovery_config_version",
    41  			Help: "The current auto discovery config version",
    42  		}, []string{"addr"}),
    43  		resolvedAddresses: extprom.NewTxGaugeVec(reg, prometheus.GaugeOpts{
    44  			Name: "auto_discovery_resolved_addresses",
    45  			Help: "The number of memcached nodes found via auto discovery",
    46  		}, []string{"addr"}),
    47  		resolverLookupsCount: promauto.With(reg).NewCounter(prometheus.CounterOpts{
    48  			Name: "auto_discovery_total",
    49  			Help: "The number of memcache auto discovery attempts",
    50  		}),
    51  		resolverFailuresCount: promauto.With(reg).NewCounter(prometheus.CounterOpts{
    52  			Name: "auto_discovery_failures_total",
    53  			Help: "The number of memcache auto discovery failures",
    54  		}),
    55  		logger: logger,
    56  	}
    57  	return p
    58  }
    59  
    60  // Resolve stores a list of nodes auto-discovered from the provided addresses.
    61  func (p *Provider) Resolve(ctx context.Context, addresses []string) error {
    62  	clusterConfigs := map[string]*clusterConfig{}
    63  	errs := errutil.MultiError{}
    64  
    65  	for _, address := range addresses {
    66  		clusterConfig, err := p.resolver.Resolve(ctx, address)
    67  		p.resolverLookupsCount.Inc()
    68  
    69  		if err != nil {
    70  			level.Warn(p.logger).Log(
    71  				"msg", "failed to perform auto-discovery for memcached",
    72  				"address", address,
    73  			)
    74  			errs.Add(err)
    75  			p.resolverFailuresCount.Inc()
    76  
    77  			// Use cached values.
    78  			p.RLock()
    79  			clusterConfigs[address] = p.clusterConfigs[address]
    80  			p.RUnlock()
    81  		} else {
    82  			clusterConfigs[address] = clusterConfig
    83  		}
    84  	}
    85  
    86  	p.Lock()
    87  	defer p.Unlock()
    88  
    89  	p.resolvedAddresses.ResetTx()
    90  	p.configVersion.ResetTx()
    91  	for address, config := range clusterConfigs {
    92  		p.resolvedAddresses.WithLabelValues(address).Set(float64(len(config.nodes)))
    93  		p.configVersion.WithLabelValues(address).Set(float64(config.version))
    94  	}
    95  	p.resolvedAddresses.Submit()
    96  	p.configVersion.Submit()
    97  
    98  	p.clusterConfigs = clusterConfigs
    99  
   100  	return errs.Err()
   101  }
   102  
   103  // Addresses returns the latest addresses present in the Provider.
   104  func (p *Provider) Addresses() []string {
   105  	p.RLock()
   106  	defer p.RUnlock()
   107  
   108  	var result []string
   109  	for _, config := range p.clusterConfigs {
   110  		for _, node := range config.nodes {
   111  			result = append(result, fmt.Sprintf("%s:%d", node.dns, node.port))
   112  		}
   113  	}
   114  	return result
   115  }