...

Source file src/github.com/go-kit/kit/sd/etcd/registrar.go

Documentation: github.com/go-kit/kit/sd/etcd

     1  package etcd
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	etcd "go.etcd.io/etcd/client/v2"
     8  
     9  	"github.com/go-kit/log"
    10  )
    11  
    12  const minHeartBeatTime = 500 * time.Millisecond
    13  
    14  // Registrar registers service instance liveness information to etcd.
    15  type Registrar struct {
    16  	client  Client
    17  	service Service
    18  	logger  log.Logger
    19  
    20  	quitmtx sync.Mutex
    21  	quit    chan struct{}
    22  }
    23  
    24  // Service holds the instance identifying data you want to publish to etcd. Key
    25  // must be unique, and value is the string returned to subscribers, typically
    26  // called the "instance" string in other parts of package sd.
    27  type Service struct {
    28  	Key           string // unique key, e.g. "/service/foobar/1.2.3.4:8080"
    29  	Value         string // returned to subscribers, e.g. "http://1.2.3.4:8080"
    30  	TTL           *TTLOption
    31  	DeleteOptions *etcd.DeleteOptions
    32  }
    33  
    34  // TTLOption allow setting a key with a TTL. This option will be used by a loop
    35  // goroutine which regularly refreshes the lease of the key.
    36  type TTLOption struct {
    37  	heartbeat time.Duration // e.g. time.Second * 3
    38  	ttl       time.Duration // e.g. time.Second * 10
    39  }
    40  
    41  // NewTTLOption returns a TTLOption that contains proper TTL settings. Heartbeat
    42  // is used to refresh the lease of the key periodically; its value should be at
    43  // least 500ms. TTL defines the lease of the key; its value should be
    44  // significantly greater than heartbeat.
    45  //
    46  // Good default values might be 3s heartbeat, 10s TTL.
    47  func NewTTLOption(heartbeat, ttl time.Duration) *TTLOption {
    48  	if heartbeat <= minHeartBeatTime {
    49  		heartbeat = minHeartBeatTime
    50  	}
    51  	if ttl <= heartbeat {
    52  		ttl = 3 * heartbeat
    53  	}
    54  	return &TTLOption{
    55  		heartbeat: heartbeat,
    56  		ttl:       ttl,
    57  	}
    58  }
    59  
    60  // NewRegistrar returns a etcd Registrar acting on the provided catalog
    61  // registration (service).
    62  func NewRegistrar(client Client, service Service, logger log.Logger) *Registrar {
    63  	return &Registrar{
    64  		client:  client,
    65  		service: service,
    66  		logger:  log.With(logger, "key", service.Key, "value", service.Value),
    67  	}
    68  }
    69  
    70  // Register implements the sd.Registrar interface. Call it when you want your
    71  // service to be registered in etcd, typically at startup.
    72  func (r *Registrar) Register() {
    73  	if err := r.client.Register(r.service); err != nil {
    74  		r.logger.Log("err", err)
    75  	} else {
    76  		r.logger.Log("action", "register")
    77  	}
    78  	if r.service.TTL != nil {
    79  		go r.loop()
    80  	}
    81  }
    82  
    83  func (r *Registrar) loop() {
    84  	r.quitmtx.Lock()
    85  	if r.quit != nil {
    86  		return // already running
    87  	}
    88  	r.quit = make(chan struct{})
    89  	r.quitmtx.Unlock()
    90  
    91  	tick := time.NewTicker(r.service.TTL.heartbeat)
    92  	defer tick.Stop()
    93  	for {
    94  		select {
    95  		case <-tick.C:
    96  			if err := r.client.Register(r.service); err != nil {
    97  				r.logger.Log("err", err)
    98  			}
    99  		case <-r.quit:
   100  			return
   101  		}
   102  	}
   103  }
   104  
   105  // Deregister implements the sd.Registrar interface. Call it when you want your
   106  // service to be deregistered from etcd, typically just prior to shutdown.
   107  func (r *Registrar) Deregister() {
   108  	if err := r.client.Deregister(r.service); err != nil {
   109  		r.logger.Log("err", err)
   110  	} else {
   111  		r.logger.Log("action", "deregister")
   112  	}
   113  
   114  	r.quitmtx.Lock()
   115  	defer r.quitmtx.Unlock()
   116  	if r.quit != nil {
   117  		close(r.quit)
   118  		r.quit = nil
   119  	}
   120  }
   121  

View as plain text