README
¶
Election Library
This is a network agnostic implementation of the leader election portion of the RAFT protocol. This library provides no
peer discovery mechanism, as such the user of this library must call SetPeers()
on the node when the list of peers
changes. Users can use any third party service discovery mechanism, such as consul, etc, k8s, or memberlist.
For our internal uses we choose https://github.com/hashicorp/memberlist such that our services have as few external dependencies as possible.
Usage
In order to use the library on the network the user must provide a SendRPC()
function at initialization time. This
function will be called when RPC communication between election.Node
is needed. A node that wishes to receive
an RPC call must in turn call Node.ReceiveRPC()
when the RPC request is received by what ever network protocol the
user implements.
You can see a simple example of this using http by looking at example_test.go
Documentation
¶
Overview ¶
Package election is a generated protocol buffer package.
It is generated from these files:
structs.proto
It has these top-level messages:
ResetElectionReq ResetElectionResp ResignReq ResignResp HeartBeatReq HeartBeatResp VoteResp VoteReq SetPeersReq SetPeersResp GetStateReq GetStateResp
Index ¶
- Constants
- Variables
- func WaitForConnect(address string, attempts int, interval time.Duration) error
- type Config
- type GetStateReq
- type GetStateResp
- type HeartBeatReq
- type HeartBeatResp
- type Node
- type NodeState
- type OnUpdate
- type RPC
- type RPCPayload
- type RPCRequest
- type RPCResponse
- type ResetElectionReq
- type ResetElectionResp
- type ResignReq
- type ResignResp
- type SendRPCFunc
- type SetPeersReq
- type SetPeersResp
- type VoteReq
- type VoteResp
Constants ¶
Variables ¶
var ErrNotLeader = errors.New("not the leader")
Functions ¶
Types ¶
type Config ¶
type Config struct { // How long we should wait for a single network operation to complete. NetworkTimeout time.Duration // How long followers should wait before they decide the leader // lost connection to peers and therefore start a new election. HeartBeatTimeout time.Duration // How long candidates should wait for an election to complete // before starting a new one. ElectionTimeout time.Duration // How long the leader should wait on heart beat responses from // followers before it decides to step down as leader and start a // new election. LeaderQuorumTimeout time.Duration // The minimum number of peers that are required to form a cluster and elect a leader. // This is to prevent a small number of nodes (or a single node) that gets disconnected // from the cluster to elect a leader (assuming the peer list is updated to exclude the // disconnected peers). Instead nodes will wait until connectivity is restored // to the quorum of the cluster. The default is zero, which means if a single node is // disconnected from the cluster, and it's peer list only includes it's self, it will elect // itself leader. If we set MinimumQuorum = 2 then no leader will be elected until the peer // list includes at least 2 peers and a successful vote has completed. MinimumQuorum int // The Initial list of peers to be considered in the election, including ourself. Peers []string // The unique id this peer identifies itself as, as found in the Peers list. // This is typically an ip:port address the node is listening to for RPC requests. UniqueID string // Called when the leader changes OnUpdate OnUpdate // The logger used errors and warning Log logrus.FieldLogger // Sends an RPC request to a peer, This function must be provided and can // utilize any network communication the implementer wishes. If context cancelled // should return an error. SendRPC SendRPCFunc }
type GetStateReq ¶
type GetStateReq struct { }
Get the current state of the node
func (*GetStateReq) Descriptor ¶
func (*GetStateReq) Descriptor() ([]byte, []int)
func (*GetStateReq) ProtoMessage ¶
func (*GetStateReq) ProtoMessage()
func (*GetStateReq) Reset ¶
func (m *GetStateReq) Reset()
func (*GetStateReq) String ¶
func (m *GetStateReq) String() string
type GetStateResp ¶
type GetStateResp struct { Leader string `protobuf:"bytes,1,opt,name=leader" json:"leader,omitempty"` State string `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"` Peers []string `protobuf:"bytes,3,rep,name=peers" json:"peers,omitempty"` }
func (*GetStateResp) Descriptor ¶
func (*GetStateResp) Descriptor() ([]byte, []int)
func (*GetStateResp) GetLeader ¶
func (m *GetStateResp) GetLeader() string
func (*GetStateResp) GetPeers ¶
func (m *GetStateResp) GetPeers() []string
func (*GetStateResp) GetState ¶
func (m *GetStateResp) GetState() string
func (*GetStateResp) ProtoMessage ¶
func (*GetStateResp) ProtoMessage()
func (*GetStateResp) Reset ¶
func (m *GetStateResp) Reset()
func (*GetStateResp) String ¶
func (m *GetStateResp) String() string
type HeartBeatReq ¶
type HeartBeatReq struct { // The leader this heart beat is from From string `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` // The current term of the leader Term uint64 `protobuf:"varint,2,opt,name=term" json:"term,omitempty"` }
Sent by the leader of the election to all followers
func (*HeartBeatReq) Descriptor ¶
func (*HeartBeatReq) Descriptor() ([]byte, []int)
func (*HeartBeatReq) GetFrom ¶
func (m *HeartBeatReq) GetFrom() string
func (*HeartBeatReq) GetTerm ¶
func (m *HeartBeatReq) GetTerm() uint64
func (*HeartBeatReq) ProtoMessage ¶
func (*HeartBeatReq) ProtoMessage()
func (*HeartBeatReq) Reset ¶
func (m *HeartBeatReq) Reset()
func (*HeartBeatReq) String ¶
func (m *HeartBeatReq) String() string
type HeartBeatResp ¶
type HeartBeatResp struct { // The follower who is responding From string `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` // The term the heart beat is for Term uint64 `protobuf:"varint,2,opt,name=term" json:"term,omitempty"` }
Response to a heart beat request
func (*HeartBeatResp) Descriptor ¶
func (*HeartBeatResp) Descriptor() ([]byte, []int)
func (*HeartBeatResp) GetFrom ¶
func (m *HeartBeatResp) GetFrom() string
func (*HeartBeatResp) GetTerm ¶
func (m *HeartBeatResp) GetTerm() uint64
func (*HeartBeatResp) ProtoMessage ¶
func (*HeartBeatResp) ProtoMessage()
func (*HeartBeatResp) Reset ¶
func (m *HeartBeatResp) Reset()
func (*HeartBeatResp) String ¶
func (m *HeartBeatResp) String() string
type Node ¶
type Node interface { // Starts the main election loop. Start(ctx context.Context) error // Cancels the election, resigns if we are leader and waits for all go // routines to complete before returning. Stop(ctx context.Context) error // Set the list of peers to be considered for the election SetPeers(ctx context.Context, peers []string) error // If leader, resigns as leader and starts a new election that we will not // participate in. returns ErrNotLeader if not currently the leader Resign(ctx context.Context) error // IsLeader is a convenience function that calls GetState() and returns true // if this node was elected leader. May block if main loop is occupied. IsLeader() bool // GetLeader is a convenience function that calls GetState() returns the // unique id of the node that is currently leader. May block if main loop is occupied. GetLeader() string // Returns the current state of this node GetState(ctx context.Context) (NodeState, error) // Called when this peer receives a RPC request from a peer ReceiveRPC(RPCRequest, *RPCResponse) }
type NodeState ¶
type NodeState GetStateResp
type RPCPayload ¶
type RPCPayload struct { RPC RPC `json:"rpc"` Request json.RawMessage `json:"request,omitempty"` Response json.RawMessage `json:"response,omitempty"` Error string `json:"error,omitempty"` }
type RPCRequest ¶
type RPCRequest struct { RPC RPC Request interface{} // contains filtered or unexported fields }
func (RPCRequest) MarshalJSON ¶
func (r RPCRequest) MarshalJSON() ([]byte, error)
func (*RPCRequest) UnmarshalJSON ¶
func (r *RPCRequest) UnmarshalJSON(s []byte) error
type RPCResponse ¶
func (RPCResponse) MarshalJSON ¶
func (r RPCResponse) MarshalJSON() ([]byte, error)
func (*RPCResponse) UnmarshalJSON ¶
func (r *RPCResponse) UnmarshalJSON(s []byte) error
type ResetElectionReq ¶
type ResetElectionReq struct { }
Resets the current state of a node to 'candidate'
func (*ResetElectionReq) Descriptor ¶
func (*ResetElectionReq) Descriptor() ([]byte, []int)
func (*ResetElectionReq) ProtoMessage ¶
func (*ResetElectionReq) ProtoMessage()
func (*ResetElectionReq) Reset ¶
func (m *ResetElectionReq) Reset()
func (*ResetElectionReq) String ¶
func (m *ResetElectionReq) String() string
type ResetElectionResp ¶
type ResetElectionResp struct { }
func (*ResetElectionResp) Descriptor ¶
func (*ResetElectionResp) Descriptor() ([]byte, []int)
func (*ResetElectionResp) ProtoMessage ¶
func (*ResetElectionResp) ProtoMessage()
func (*ResetElectionResp) Reset ¶
func (m *ResetElectionResp) Reset()
func (*ResetElectionResp) String ¶
func (m *ResetElectionResp) String() string
type ResignReq ¶
type ResignReq struct { }
Asks the node to resign as leader
func (*ResignReq) Descriptor ¶
func (*ResignReq) ProtoMessage ¶
func (*ResignReq) ProtoMessage()
type ResignResp ¶
type ResignResp struct { // True if the receiver is leader and stepped down Success bool `protobuf:"varint,1,opt,name=success" json:"success,omitempty"` }
func (*ResignResp) Descriptor ¶
func (*ResignResp) Descriptor() ([]byte, []int)
func (*ResignResp) GetSuccess ¶
func (m *ResignResp) GetSuccess() bool
func (*ResignResp) ProtoMessage ¶
func (*ResignResp) ProtoMessage()
func (*ResignResp) Reset ¶
func (m *ResignResp) Reset()
func (*ResignResp) String ¶
func (m *ResignResp) String() string
type SendRPCFunc ¶
type SendRPCFunc func(context.Context, string, RPCRequest, *RPCResponse) error
type SetPeersReq ¶
type SetPeersReq struct { // A list of peers Peers []string `protobuf:"bytes,1,rep,name=peers" json:"peers,omitempty"` }
Set the peers this node will consider during the election
func (*SetPeersReq) Descriptor ¶
func (*SetPeersReq) Descriptor() ([]byte, []int)
func (*SetPeersReq) GetPeers ¶
func (m *SetPeersReq) GetPeers() []string
func (*SetPeersReq) ProtoMessage ¶
func (*SetPeersReq) ProtoMessage()
func (*SetPeersReq) Reset ¶
func (m *SetPeersReq) Reset()
func (*SetPeersReq) String ¶
func (m *SetPeersReq) String() string
type SetPeersResp ¶
type SetPeersResp struct { }
func (*SetPeersResp) Descriptor ¶
func (*SetPeersResp) Descriptor() ([]byte, []int)
func (*SetPeersResp) ProtoMessage ¶
func (*SetPeersResp) ProtoMessage()
func (*SetPeersResp) Reset ¶
func (m *SetPeersResp) Reset()
func (*SetPeersResp) String ¶
func (m *SetPeersResp) String() string
type VoteReq ¶
type VoteReq struct { // The candidate who is requesting the targets vote Candidate string `protobuf:"bytes,1,opt,name=candidate" json:"candidate,omitempty"` // The term this vote is for. Term uint64 `protobuf:"varint,2,opt,name=term" json:"term,omitempty"` }
A vote request sent to all peers at the start of an election.
func (*VoteReq) Descriptor ¶
func (*VoteReq) GetCandidate ¶
func (*VoteReq) ProtoMessage ¶
func (*VoteReq) ProtoMessage()
type VoteResp ¶
type VoteResp struct { // The candidate who responded Candidate string `protobuf:"bytes,1,opt,name=candidate" json:"candidate,omitempty"` // The term this vote response is for Term uint64 `protobuf:"varint,2,opt,name=term" json:"term,omitempty"` // If the Vote was granted by this node Granted bool `protobuf:"varint,3,opt,name=granted" json:"granted,omitempty"` }
func (*VoteResp) Descriptor ¶
func (*VoteResp) GetCandidate ¶
func (*VoteResp) GetGranted ¶
func (*VoteResp) ProtoMessage ¶
func (*VoteResp) ProtoMessage()