reception

package module
v0.0.0-...-de89012 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2018 License: MIT Imports: 20 Imported by: 0

README

Reception

GoDoc Build Status Maintainability Test Coverage

Service discovery and cluster state reporter for Go services.

Example

A client can be created by dialing the backing service discovery service. A list of available backing services are shown below.

client, err := DialConsul("localhost:8500")
client, err := DialEtcd("localhost:2379")
client, err := DialExhibitor("localhost:8080/")
client, err := DialZk("localhost:2181")

Each dial function takes a set of optional configuration parameters. For example, a consul client can be configured with specific health check interval values. See the godoc for a complete list of options for each client.

client, err := DialConsul(
    "localhost:8500",
    WithCheckInterval(time.Second),
    WithCheckTimeout(time.Second * 5),
    WithCheckDeregisterTimeout(time.Second * 30),
)
Registration

Given a client, the current process can register itself as an instance of a service. In the following, an API instance registers itself with a unique identifier, a means of accessing it (host and port pair), and a set of attributes which may be useful to other instances of the service.

service, err := MakeService(
    "api",                      // service name
    "mesos-agent1.example.com", // host
    23423,                      // port
    map[string]string{          // attributes
        "external": "true",
    },
)

if err != nil {
    //
}

if err := client.Register(service, onDisconnect); err != nil {
    //
}

The on-disconnect function is called whenever the connection to the backing service discovery service is in question. This may be nil or a function that simply logs the state, but in some extreme circumstances the instance may need to stop processing input immediately (things that require exactly one active process). In this case, the on-disconnect function may take extreme action:

func onDisconnect(err error) {
    fmt.Printf("Disconnected from cluster, resigning!\n")
    os.Exit(1)
}
Listing

A client may list all available instances of a service by name. This gives the current state of a service but may include unhealthy instances that have not been yet removed from the list (if they are still within their deregister timeout).

services, err := client.ListServices("api")
if err != nil {
    // handle error
}

addrs := []string{}
for _, service := range services {
    addrs = append(addrs, fmt.Sprintf("%s:%d", service.Host, service.Port))
}

fmt.Printf("There are %d active services: %s\n", len(addrs), strings.Join(addrs, ", "))
Watching

A client may inform you whenever the instances of a service changes. This is an efficient way of keeping up-to-date on a service state without repeatedly calling ListServices.

watcher := client.NewWatcher("api")
ch, err := watcher.Start()
if err != nil {
    // handle error
}

for update := range ch {
    if ch.Err != nil {
        // handle error
    } else {
        for _, service := range update.Services {
            fmt.Printf("%s is live\n", service.ID)
        }
    }
}

A watcher can be stopped by calling its Stop method from another goroutine.

Election

A client also provides a mechanism for single-leader elections. The Elect method blocks until the current process is elected leader. An error may be returned when the election is cancelled, or if there is an error connecting to the backing service.

elector := NewElector(
    client,
    "reaper",
    WithDisconnectionCallback(onDisconnect),
)

go func() {
    for {
        fmt.Printf("current leader is %#v\n", elector.Leader())
        <-time.After(time.Second)
    }()
}()

if err := elector.Elect(); err == nil {
    fmt.Printf("I'm the leader!\n")
}

A process can withdraw itself from the election process by calling the elector's Cancel method from another goroutine. The current leader's service data can be retrieved with the Leader method. This will only return a useful value once the election has been started (not before the initial remote response from the call to Elect).

License

Copyright (c) 2017 Eric Fritz

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBadResponse occurs when exhibitor returns an unparseable response.
	ErrBadResponse = errors.New("could not decode exhibitor response")

	// ErrEmptyServerList occurs when exhibitor lists no available nodes.
	ErrEmptyServerList = errors.New("exhibitor is alive but returned no servers")
)
View Source
var ErrElectionCanceled = errors.New("election canceled")

ErrElectionCanceled occurs when an election is concurrently cancelled.

View Source
var ErrIllegalHost = errors.New("illegal host")

ErrIllegalHost occurs when a health check server is created with an illegal host value.

View Source
var ErrNoConsulHealthCheck = errors.New("consul has not pinged in disconnect timeout")

ErrNoConsulHealthCheck occurs when Consul has not contacted the health endpoint of a registered service for a duration (its deregister timeout).

View Source
var ErrZkDisconnect = errors.New("zk session has been disconnected")

ErrZkDisconnect occurs when the session to Zookeeper has been disconnected.

Functions

This section is empty.

Types

type Attributes

type Attributes map[string]string

Attributes are additional metadata about a service.

type Client

type Client interface {
	// Register links the current process as an instance of the given service.
	// The on-disconnect function, if non-nil, is called if the connection to
	// the remote service discovery service is severed (this indicates the
	// possibliity that a node has seen the current process de-register from
	// the remote service).
	Register(service *Service, onDisconnect func(error)) error

	// ListServices returns all currently registered instances of the service
	// with the given name.
	ListServices(name string) ([]*Service, error)

	// NewWatcher creates a watch which is updated whenever the live node list
	// of the serfvice with the given name changes. Some implementations may
	// call this as a heartbeat, providing the same set of services as the
	// previous update.
	NewWatcher(name string) Watcher
}

Client provides abstractions for registering and querying the current set of live instances of a service within a cluster.

func DialConsul

func DialConsul(addr string, configs ...ConsulConfigFunc) (Client, error)

DialConsul creates a new Client by connecting to a Consul node.

func DialEtcd

func DialEtcd(addr string, configs ...EtcdConfigFunc) (Client, error)

DialEtcd will create a new Client by connecting to an Etcd node.

func DialExhibitor

func DialExhibitor(addr string, configs ...ZkConfigFunc) (Client, error)

DialExhibitor will create a new Client by choosing a random server from the Exhibitor server list. See DialZk for additional details.

func DialZk

func DialZk(addr string, configs ...ZkConfigFunc) (Client, error)

DialZk will create a new Client by connecting directly to a Zookeeper node. This method will block while the Zookeeper session becomes connected.

func NewConsulClient

func NewConsulClient(client *consul.Client, configs ...ConsulConfigFunc) Client

NewConsulClient creates a new Client from an existing Consul connection.

func NewEtcdClient

func NewEtcdClient(client etcd.Client, configs ...EtcdConfigFunc) Client

NewEtcdClient creates a new Client from an existing Etcd connection.

func NewZkClient

func NewZkClient(conn *zk.Conn, events <-chan zk.Event, configs ...ZkConfigFunc) Client

NewZkClient creates a new Client from an existing Zookeeper connection.

type ConsulConfigFunc

type ConsulConfigFunc func(*consulConfig)

ConsulConfigFunc is provided to DialEtcd to change the default client parameters.

func WithCheckDeregisterTimeout

func WithCheckDeregisterTimeout(timeout time.Duration) ConsulConfigFunc

WithCheckDeregisterTimeout sets the timeout after which Consul will consider the process unhealthy.

func WithCheckInterval

func WithCheckInterval(timeout time.Duration) ConsulConfigFunc

WithCheckInterval sets Consul's interval for health checks to this process.

func WithCheckTimeout

func WithCheckTimeout(timeout time.Duration) ConsulConfigFunc

WithCheckTimeout sets Consul's TTL for health checks to this process.

func WithHost

func WithHost(host string) ConsulConfigFunc

WithHost sets the host of the current process. This must be set before calling the Register function, otherwise the proper address (resolvable outside of the current machine) cannot be given to Consul for health check information.

func WithLogger

func WithLogger(logger Logger) ConsulConfigFunc

WithLogger sets the logger sets the logger which will print the access logs of the health check server.

func WithPort

func WithPort(port int) ConsulConfigFunc

WithPort sets the port on which the health check server should listen. By default, this will be a dynamically bound port (any free port on the machine).

type Elector

type Elector interface {
	// Elect will begin an election. The current process is put into
	// the pool of candidates and then waits until the current leader
	// (if one exists) disconnects from the cluster. This method will
	// block until the current process has been elected.
	Elect() error

	// Leader will return the service that was elected in the most
	// recent election. This method will only return nil until the
	// goroutine in which Elect was called has received a response
	// from the remote server.
	Leader() *Service

	// Cancel the election and unblock the Elect function.
	Cancel()
}

func NewElector

func NewElector(client Client, name string, configs ...ElectorConfigFunc) Elector

NewElector create an elector for the service using the given name and backing client.

type ElectorConfigFunc

type ElectorConfigFunc func(*elector)

ElectorConfigFunc is provided to NewElector to change the default elector parameters.

func WithAttributes

func WithAttributes(attributes Attributes) ElectorConfigFunc

WithAttributes sets the attributes of the instance participating in the election.

func WithDisconnectionCallback

func WithDisconnectionCallback(onDisconnect func(error)) ElectorConfigFunc

WithDisconnectionCallback sets the callback function which is invoked if the backing client disconnects after the election has unblocked.

func WithHostAndPort

func WithHostAndPort(host string, port int) ElectorConfigFunc

WithHostAndPort sets the host and port of the instance participating in the election.

func WithServiceID

func WithServiceID(serviceID string) ElectorConfigFunc

WithServiceID sets the service ID of the instance participating in the election. If one is not set, then one is randomly generated.

type EtcdConfigFunc

type EtcdConfigFunc func(*etcdConfig)

EtcdConfigFunc is provided to DialEtcd to change the default client parameters.

func WithEtcdPrefix

func WithEtcdPrefix(prefix string) EtcdConfigFunc

WithEtcdPrefix sets the prefix of all registered services.

func WithRefreshInterval

func WithRefreshInterval(refreshInterval time.Duration) EtcdConfigFunc

WithRefreshInterval sets the interval on which service nodes are refreshed.

func WithTTL

func WithTTL(ttl time.Duration) EtcdConfigFunc

WithTTL sets the time that a registered service can live without an update.

type Logger

type Logger interface {
	// Prints logs a message. Arguments should be handled in the manner of fmt.Printf.
	Printf(format string, args ...interface{})
}

Logger is an interface to the logger the client writes to.

func NewNilLogger

func NewNilLogger() Logger

type Service

type Service struct {
	ID         string     `json:"-"`
	Name       string     `json:"-"`
	Address    string     `json:"address"`
	Port       int        `json:"port"`
	Attributes Attributes `json:"attributes"`
}

Service holds metadata about an instance of a service.

func MakeService

func MakeService(name, addr string, port int, attributes Attributes) (*Service, error)

MakeService will instantiate a Service instance with a random ID.

type ServiceState

type ServiceState struct {
	Services []*Service
	Err      error
}

ServiceState contains either the current set of lvie instance of a service or an error which occurred when querying the remote service discovery service.

type Watcher

type Watcher interface {
	// Start creates a channel on which updates are pushed.
	Start() (<-chan *ServiceState, error)

	// Stop halts the background processes spawned by the Start method.
	Stop()
}

Watcher provides a mechanism to receive push-based updates about the current set of live instances of a service within a cluster.

type ZkConfigFunc

type ZkConfigFunc func(*zkConfig)

ZkConfigFunc is provided to DialExhibitor and DialZk to change the default client parameters.

func WithZkPrefix

func WithZkPrefix(prefix string) ZkConfigFunc

WithZkPrefix will change the root path in which znodes are created and queried. This allows isolation between different programs using the same Zookeeper cluster.

Jump to

Keyboard shortcuts

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