func (c *Coordinator) loop(fn loopFunc, interval time.Duration, reason string) chan struct{} {
	done := make(chan struct{})
	go func() {
		ticker := c.ticker(interval)
		defer close(done)
		for {
			select {
			case <-ticker():
				if err := fn(); err != nil {
					c.Logger.WithError(err).Errorf("Worker %s failed to %s", c.WorkerId, reason)
				}
			case <-done:
				return
			}
		}
	}()
	return done
}
loop spawn a goroutine and returns a "done" channel that linked to this goroutine.
the interval used to create a ticker to run the given loopFunc each x time and
the reason string used for logging.
package lease
import "time"
type Coordinator struct {
	*Config
	Manager Manager
	Renewer Renewer
	Taker   Taker
	stopTaker  chan struct{}
	stopRenwer chan struct{}
}
type loopFunc func() error
func New(config *Config) Leaser {
	config.defaults()
	manager := &LeaseManager{config, newSerializer()}
	return &Coordinator{
		Config:  config,
		Manager: manager,
		Renewer: &leaseHolder{
			Config:     config,
			manager:    manager,
			heldLeases: make(map[string]*Lease),
		},
		Taker: &leaseTaker{
			Config:    config,
			manager:   manager,
			allLeases: make(map[string]*Lease),
		},
	}
}
func (c *Coordinator) Start() error {
	if err := c.Manager.CreateLeaseTable(); err != nil {
		return err
	}
	takerIntervalMills := (c.ExpireAfter + c.epsilonMills) * 2
	renewerIntervalMills := c.ExpireAfter/3 - c.epsilonMills
	c.stopTaker = c.loop(c.Taker.Take, takerIntervalMills, "take leases")
	c.stopRenwer = c.loop(c.Renewer.Renew, renewerIntervalMills, "renew leases")
	c.Logger.Infof("Start coordinator with failover time %s, and epsilon %s. "+
		"LeaseCoordinator will renew leases every %s, take leases every %s "+
		"and steal %d lease(s) at a time.",
		c.ExpireAfter,
		c.epsilonMills,
		renewerIntervalMills,
		takerIntervalMills,
		c.MaxLeasesToStealAtOneTime)
	return nil
}
func (c *Coordinator) Stop() {
	c.Logger.Info("stopping coordinator")
	c.stopTaker <- struct{}{}
	<-c.stopTaker
	c.stopRenwer <- struct{}{}
	<-c.stopRenwer
	c.Logger.Info("stopped coordinator")
}
func (c *Coordinator) GetHeldLeases() []Lease {
	return c.Renewer.GetHeldLeases()
}
func (c *Coordinator) Delete(l Lease) error {
	return c.Manager.DeleteLease(&l)
}
func (c *Coordinator) Create(lease Lease) (Lease, error) {
	clease, err := c.Manager.CreateLease(&lease)
	if err != nil {
		return lease, err
	}
	return *clease, nil
}
func (c *Coordinator) Update(lease Lease) (Lease, error) {
	var heldLease Lease
	for _, hlease := range c.Renewer.GetHeldLeases() {
		if lease.Key == hlease.Key {
			heldLease = hlease
			break
		}
	}
	if heldLease.hasNoOwner() {
		return lease, ErrLeaseNotHeld
	}
	if heldLease.concurrencyToken != lease.concurrencyToken {
		return lease, ErrTokenNotMatch
	}
	ulease, err := c.Manager.UpdateLease(&lease)
	if err != nil {
		return lease, err
	}
	return *ulease, nil
}
func (c *Coordinator) ForceUpdate(lease Lease) (Lease, error) {
	ulease, err := c.Manager.UpdateLease(&lease)
	if err != nil {
		return lease, err
	}
	return *ulease, nil
}