1
0
Fork 0

Add leadership election

Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
Emile Vauge 2016-08-18 13:03:10 +02:00
parent 5a0440d6f8
commit bea5ad3f13
No known key found for this signature in database
GPG key ID: D808B4C167352E59
7 changed files with 138 additions and 29 deletions

View file

@ -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()
}
}