Skip to content
This repository has been archived by the owner on Nov 26, 2017. It is now read-only.

roboll/elector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

elector

a general purpose flexible leader election utility

about

elector is a general purpose leader election utility, providing a pluggable backend, as well as a flexible handlers for election events.

cli

The cli for elector accepts a leader-begin-command and leader-end-command; the former executed during transitions to leader state, and the latter during transitions from leader state. (leader-begin-command and leader-end-command are shell commands)

library

The elector library defines two basic interfaces; ElectionBackend, a backend that sources leader election events from a backend system, and Handler, a function executed after state transitions to perform arbitrary commands.

An ElectorBackend defines ElectionLoop, which is not expected to return, barring unrecoverable errors. It should continue to source election events and send elector.State messages to the updates channel (StateLeader, StateNotLeader, StateError). The reconciliation loop handles the transitions between states and executes the necessary handlers.

A Handler is executed by the reconciliation loop when state transitions occur to and from leader state. It is a function that accepts no arguments and returns and error in case it cannot complete it's task. Handlers should be resilient, i.e. if a handler receives an error that is recoverable it should handle it's own retry logic. The elector will attempt retries in a failure, but because it has not knowledge of the underlying command, has less flexibility in its operation. In case of an error, the reconciliation loop will transition to StateError, ensuring that the elector relinquishes master state and waits a given timeout before resuming candidacy.

extending / usage

To define an ElectorBackend take a look at the console implementation - it is very straightforward.

To define custom handlers take a look at the pre-defined handlers, also very straightforward.

For custom usage of an elector, take a look at it's usage in main. Create an elector.Elector, define it's backend and handlers, and call Run().

backends

etcd-lock

The etcd-lock backend is supported by etcd-lock. It acquires a lock on a node (keyspace) in etcd and continually updates the ttl on that node to maintain leader state. It supports full tls security.

console

The console backend is used for testing proper execution of state transitions and handlers. It sources election events from the console, i.e. your terminal. It allows input of text events (LEADER, NOTLEADER, ERROR).

reconciliation loop logic

Because elector manages local state with the state of a remote leader election, it requires logic to reconcile local state machine with messages from the remote system. The reconciliation loop behaves as follows:

    message rcvd:
		case StateLeader:
			if state == StateNotLeader
				err = exec BeginLeaderHandler
				if not err
					state = StateLeader
				if err
					<- StateError

		case StateNotLeader:
			if state == StateLeader
				err = exec EndLeaderHandler
				if not err
					state = StateNotLeader
				if err
					<- StateError

		case Error:
			if state == StateLeader
				err = exec EndLeaderHandler
				if not err
					state = StateError
					exec ErrorHandler (timeout)
					state = StateNotLeader
				if err
					<- StateError

WARNING: after a StateError message, if the EndLeaderHandler fails repeatedly, there is a condition where the local system may continue to operate as leader (as is the case with any failure of the EndLeaderHandler). The loop will continue to retry every 5s for 12 attempts, after which it will exit the system and log failure messages.