Add leadership election
Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
parent
5a0440d6f8
commit
bea5ad3f13
7 changed files with 138 additions and 29 deletions
|
@ -6,22 +6,34 @@ import (
|
|||
"github.com/containous/traefik/safe"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/docker/leadership"
|
||||
"golang.org/x/net/context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Leadership allows leadership election using a KV store
|
||||
type Leadership struct {
|
||||
types.Cluster
|
||||
*safe.Pool
|
||||
*types.Cluster
|
||||
candidate *leadership.Candidate
|
||||
}
|
||||
|
||||
// NewLeadership creates a leadership
|
||||
func NewLeadership(ctx context.Context, cluster *types.Cluster) *Leadership {
|
||||
return &Leadership{
|
||||
Pool: safe.NewPool(ctx),
|
||||
Cluster: cluster,
|
||||
candidate: leadership.NewCandidate(cluster.Store, cluster.Store.Prefix+"/leader", cluster.Node, 20*time.Second),
|
||||
}
|
||||
}
|
||||
|
||||
// Participate tries to be a leader
|
||||
func (l *Leadership) Participate(pool *safe.Pool, isElected func(bool)) {
|
||||
pool.Go(func(stop chan bool) {
|
||||
l.candidate = leadership.NewCandidate(l.Store, l.Store.Prefix+"/leader", l.Node, 30*time.Second)
|
||||
func (l *Leadership) Participate(pool *safe.Pool) {
|
||||
pool.GoCtx(func(ctx context.Context) {
|
||||
log.Debugf("Node %s running for election", l.Cluster.Node)
|
||||
defer log.Debugf("Node %s no more running for election", l.Cluster.Node)
|
||||
backOff := backoff.NewExponentialBackOff()
|
||||
operation := func() error {
|
||||
return l.run(l.candidate, stop, isElected)
|
||||
return l.run(l.candidate, ctx)
|
||||
}
|
||||
|
||||
notify := func(err error, time time.Duration) {
|
||||
|
@ -36,21 +48,31 @@ func (l *Leadership) Participate(pool *safe.Pool, isElected func(bool)) {
|
|||
|
||||
// Resign resigns from being a leader
|
||||
func (l *Leadership) Resign() {
|
||||
if l.candidate != nil {
|
||||
l.candidate.Resign()
|
||||
}
|
||||
l.candidate.Resign()
|
||||
log.Infof("Node %s resined", l.Cluster.Node)
|
||||
}
|
||||
|
||||
func (l *Leadership) run(candidate *leadership.Candidate, stop chan bool, isElected func(bool)) error {
|
||||
func (l *Leadership) run(candidate *leadership.Candidate, ctx context.Context) error {
|
||||
electedCh, errCh := candidate.RunForElection()
|
||||
for {
|
||||
select {
|
||||
case elected := <-electedCh:
|
||||
isElected(elected)
|
||||
l.onElection(elected)
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-stop:
|
||||
case <-ctx.Done():
|
||||
l.candidate.Resign()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Leadership) onElection(elected bool) {
|
||||
if elected {
|
||||
log.Infof("Node %s elected leader ♚", l.Cluster.Node)
|
||||
l.Start()
|
||||
} else {
|
||||
log.Infof("Node %s elected slave ♝", l.Cluster.Node)
|
||||
l.Stop()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue