elector

package
v0.0.0-...-53b0845 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 21, 2020 License: Apache-2.0 Imports: 10 Imported by: 0

README

dcos-go/elector

A ZK-based leadership election library

Overview

This library allows multiple nodes to elect a leader. This works by creating ephemeral and sequential znodes as the children of a base node. The child of the base node that has the lowest sequence number is agreed upon to be the leader.

Note that this elector assumes that on any error from ZK (partition or otherwise) that the state of the election cannot be reliably determined. If an error is received on the events channel, the client should shut down (and presumably, let the init system restart it).

Usage

ident := "127.0.0.1" // set this to your IP address
basePath := "/services/my-service/leader"
connector := NewConnection([]string{"127.0.0.1:2181"}, ConnectionOpts{})
var acl []zk.ACL // set this to something useful, or leave nil

el, err := Start(ident, basePath, acl, connector)
if err != nil {
	log.Fatal(err)
}

go func() {
	for event := range el.Events() {
		if event.Err != nil {
			log.Fatal("Leadership failed. Exiting...", event.Err)
		}
		if event.Leader {
			log.Info("I am now the leader")
		} else {
			log.Info("I am not the leader anymore")
		}
	}
}()

http.Handle("/v1/leader", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	leader := el.LeaderIdent()
	if leader == "" {
		fmt.Fprintln(w, "leader unknown")
		return
	}
	fmt.Fprintf(w, "leader is currently: %s\n", leader)
}))

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Conn

type Conn interface {
	Get(path string) ([]byte, *zk.Stat, error)
	Exists(path string) (bool, *zk.Stat, error)
	Create(path string, data []byte, flags int32, acl []zk.ACL) (string, error)
	CreateProtectedEphemeralSequential(path string, data []byte, acl []zk.ACL) (string, error)
	ChildrenW(path string) ([]string, *zk.Stat, <-chan zk.Event, error)
}

Conn represents a connection to ZK.

type ConnAdapter

type ConnAdapter struct {
	GetF                                func(path string) ([]byte, *zk.Stat, error)
	ExistsF                             func(path string) (bool, *zk.Stat, error)
	CreateF                             func(path string, data []byte, flags int32, acl []zk.ACL) (string, error)
	CreateProtectedEphemeralSequentialF func(path string, data []byte, acl []zk.ACL) (string, error)
	ChildrenWF                          func(path string) ([]string, *zk.Stat, <-chan zk.Event, error)
}

ConnAdapter represents a connection to ZK.

func (ConnAdapter) ChildrenW

func (c ConnAdapter) ChildrenW(path string) ([]string, *zk.Stat, <-chan zk.Event, error)

ChildrenW implements Conn.

func (ConnAdapter) Create

func (c ConnAdapter) Create(path string, data []byte, flags int32, acl []zk.ACL) (string, error)

Create implements Conn.

func (ConnAdapter) CreateProtectedEphemeralSequential

func (c ConnAdapter) CreateProtectedEphemeralSequential(path string, data []byte, acl []zk.ACL) (string, error)

CreateProtectedEphemeralSequential implements Conn.

func (ConnAdapter) Exists

func (c ConnAdapter) Exists(path string) (bool, *zk.Stat, error)

Exists implements Conn.

func (ConnAdapter) Get

func (c ConnAdapter) Get(path string) ([]byte, *zk.Stat, error)

Get implements Conn.

type ConnectionOpts

type ConnectionOpts struct {
	// ConnectTimeout is the timeout to make the initial connection to ZK.
	ConnectTimeout time.Duration

	// InitialSessionTimeout is how long to wait for a valid session to
	// be established once the connection happens.
	InitialSessionTimeout time.Duration

	// Auth represents authentication details. If left alone, no auth will
	// be performed
	Auth struct {
		Schema string
		Secret []byte
	}
}

ConnectionOpts are used when creating a new Zk connection

type Connector

type Connector interface {
	// Connect returns a ZK connection and events channel
	Connect() (Conn, <-chan zk.Event, error)

	// Close should ensure the ZK connection is closed.
	Close() error
}

Connector specifies a way to connect to ZK.

func ExistingConnection

func ExistingConnection(conn Conn, events <-chan zk.Event) Connector

ExistingConnection returns an existing connection. Since it consumes from the zk.Event channel, it might be necessary for the client to fan out incoming events on the original channel to a new one so that events are not lost.

The existing connection should have already established a session before calling this method

func NewConnection

func NewConnection(addrs []string, opts ConnectionOpts) Connector

NewConnection returns a Connector that creates a new ZK connection

type Elector

type Elector struct {
	// contains filtered or unexported fields
}

Elector handles leadership elections

func Start

func Start(ident string, basePath string, acl []zk.ACL, connector Connector) (*Elector, error)

Start builds a new elector and runs it in the background.

The 'ident' parameter is the content that the elector will store inside of it's znode data. This will typically be the IP address of the client of the elector.

The 'basePath' parameter is the znode under which the leader election will happen.

The 'acl' will be set on any nodes that must be created

func (*Elector) Close

func (e *Elector) Close() error

Close closes the underlying ZK connection. Clients should call Close() when abandoning elector efforts in order to quickly delete any ephemeral nodes that were created as a part of the election process.

func (*Elector) Events

func (e *Elector) Events() <-chan Event

Events returns a channel on which Events will be sent.

func (*Elector) LeaderIdent

func (e *Elector) LeaderIdent() string

LeaderIdent returns the current leader, or "" if no current leader is known yet.

type Event

type Event struct {
	// Leader is true if the elector that produced it is the leader
	Leader bool

	// Err represents an error event. If this is non-nil, the other fields
	// in the event must be ignored, and most clients will want to
	// shut down if Err is non-nil, since leadership cannot be guaranteed
	// in that case.
	//
	// When an err is sent, the Elector should no longer be considered
	// usable.
	Err error
}

Event is sent on the Elector's Events() channel.

func (Event) String

func (e Event) String() string

type IElector

type IElector interface {
	// LeaderIdent returns the current leader of the cluster, or "" if
	// the current leader is not known.
	LeaderIdent() string

	// Events returns a channel from which the client should consume events
	// from the elector.  The channel will be closed after an error event
	// is sent, as the elector is no longer usable from that point on.
	Events() <-chan Event

	// Close tidies up any applicable connection details to ZK. Clients
	// should call then when the elector is no longer needed
	Close() error
}

IElector is the interface to which the Elector must adhere. Clients may choose to use this, but the Start() method will return a concrete type, keeping in line with 'return concrete types, accept interfaces'.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL