sereno

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

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

Go to latest
Published: Mar 24, 2016 License: Apache-2.0 Imports: 13 Imported by: 0

README

Sereno

A Go library for working with distributed systems using Etcd for coordination.

Build Status GoDoc

Status

A work in progress. But I'm planning to have it usable in a couple of months. (~Jan 2016).

Why Sereno?

Sereno means night watchman in Spanish and since this project is inspired by the curator library for zookeeper, it seemed like a good choice.

Inspiration:

Inspired by the recipes in the curator library. http://curator.apache.org/curator-recipes/index.html

Sereno's Recipes:

Leader Election :

coming soon!

Distributed Counters :

On server 1

	kapi := client.NewKeysAPI(c) // the etcd client form: https://github.com/coreos/etcd/tree/master/client
	cntr, err := sereno.NewCounter(context.Background(), "counter001", kapi)
	if err != nil {
		log.Fatalf("error:", err)
	}
	err := cntr.Inc(1)

On server 2

	kapi := client.NewKeysAPI(c) // the etcd client form: https://github.com/coreos/etcd/tree/master/client
	cntr, err := sereno.NewCounter(context.Background(), "counter001", kapi)
	if err != nil {
		log.Fatalf("error:", err)
	}
	err := cntr.Inc(1)
Distributed WaitGroup :

A distributed version of golang's WaitGroup.

Example:

Parent

i.e. waiting for workers to finish.

	kapi := client.NewKeysAPI(c) // the etcd client form: https://github.com/coreos/etcd/tree/master/client
	dwg, err := sereno.NewWaitGroup(context.Background(), "workgroup0001", kapi)
	if err != nil {
		log.Fatalf("error:", err)
	}
	dwg.Add(5)
	dwg.Wait()

Child

i.e. the ones doing the work that the "parent".

	kapi := client.NewKeysAPI(c) // the etcd client form: https://github.com/coreos/etcd/tree/master/client
	dwg, err := sereno.NewWaitGroup(context.Background(), "workgroup0001", kapi)
	if err != nil {
		log.Fatalf("error:", err)
	}
	// Do some Work.....
	dwg.Done()
Topic Based PubSub :

This is a topic based pub/sub message bus using etcd. This solution isn't going to be good for high volume message (see Kafka8+sarama, gnatsd,etc if you need high throughput message loads). From my testing this does fine upto about 200 msgs/second.

So with that caveat why use it? Convenience! If your already uses this library and you don't' need message throughput it nice to be able to just use it without having to setup one more service and bring in more dependencies. Im using it to signal my works to begin tasks, and using a Distrusted WaitGroup to signal when they've all finished.

####### Example:

Publisher:

	kapi := client.NewKeysAPI(c) // the etcd client form: https://github.com/coreos/etcd/tree/master/client
	pub, err := sereno.NewPubSubTopic(context.Background(), "topic42", kapi)
	if err != nil {
		log.Fatalf("error:", err)
	}
	err := pub.Publish([]byte("newwork:taskid:123456789"))
	if err != nil {
		log.Fatalf("error:", err)
	}

Subscriber:

    sub, err := sereno.NewPubSubTopic(context.Background(), "topic42", kapi)
	if err != nil {
		log.Fatalf("error:", err)
	}
	subchan, err := sub.Subscribe()
	if err != nil {
		log.Fatalf("error:", err)
	}
	for msgout := range subchan {
		if msgout.Err != nil {
			err := msgout.Err
			if err == context.Canceled {
				return
			} else if err == context.DeadlineExceeded {
				return
			}
			log.Fatalf("error: %v", msgout.Err)
		}
		log.Println("new message: %v", string(msgout.Msg))
	}
Node keep alive :

This struct is useful to announcing that this node is still alive. A common use of this pattern is to refresh an etcd node's ttl every so often (i.e. 30 seconds), so that a collection of actors can be detect when other actors enter or leave the topology.

This is a building block for patterns like Leader Election, for detecting nodes leaving your topology.

func main(){
	kapi := client.NewKeysAPI(c) // the etcd client form: https://github.com/coreos/etcd/tree/master/client
	keepalive, err := sereno.NewNodeKeepAlive(context.Background(), "service/api/node0001", 30*time.Second, kapi)
	if err != nil {
		log.Fatalf("error:", err)
	}
	defer keepalive.Stop() //[Optional] just explicitly stops the keepalive but it doesn't remove the etcd node.
	//... 
}
Time Sortable Disbuited UUIDs (via SonyFlake).

Sonyflake is a distributed unique ID generator inspired by Twitter's Snowflake.
A Sonyflake ID is composed of

39 bits for time in units of 10 msec
 8 bits for a sequence number
16 bits for a machine id
	msgid, err := sereno.NextId()
	if err != nil {
		log.Fatalf("error:", err)
	}
	//use that msgid, its a uint64 that is sortable by creation time.  see [SonyFlake](https://github.com/sony/sonyflake)

Documentation

Index

Constants

This section is empty.

Variables

View Source
var CASErrorOutOfRetries error = fmt.Errorf("error trying to do a compare and swap of a value.  out of retries.")
View Source
var DefaultTTL time.Duration = 24 * time.Hour
View Source
var UseDebugdlogging = false

LOGGING

View Source
var Usedtracedlogging = false

Functions

func IsCompareAndSwapFailure

func IsCompareAndSwapFailure(err error) bool

func IsKeyNotFound

func IsKeyNotFound(err error) bool

func IsNodeExists

func IsNodeExists(err error) bool

func NextId

func NextId() (uint64, error)

func TTLRefreshDur

func TTLRefreshDur(nodettl time.Duration) time.Duration

func WgCount

func WgCount(wg *DistributedWaitGroup) (int, error)

WgCount is a helper function to extract the number of workers this waitgroup is currently waiting on. useful for tests that aren't exiting.

Types

type CounterUpdate

type CounterUpdate struct {
	Cnt int
	Err error
}

type DistributedCounter

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

func NewCounter

func NewCounter(ctx context.Context, cid string, kapi etcdc.KeysAPI) (*DistributedCounter, error)

func NewDistributedCounter

func NewDistributedCounter(ctx context.Context, keyid string, ttl time.Duration, kapi etcdc.KeysAPI) (*DistributedCounter, error)

func (*DistributedCounter) Dec

func (c *DistributedCounter) Dec(n int) error

func (*DistributedCounter) Inc

func (c *DistributedCounter) Inc(n int) error

func (*DistributedCounter) Set

func (c *DistributedCounter) Set(val int) error

func (*DistributedCounter) UnWatch

func (c *DistributedCounter) UnWatch()

func (*DistributedCounter) Val

func (c *DistributedCounter) Val() (int, error)

type DistributedWaitGroup

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

func NewDistributedWaitGroup

func NewDistributedWaitGroup(ctx context.Context, ttl time.Duration, wgkeyid string, kapi etcdc.KeysAPI) (*DistributedWaitGroup, error)

func NewWaitGroup

func NewWaitGroup(ctx context.Context, wgid string, kapi etcdc.KeysAPI) (*DistributedWaitGroup, error)

func (*DistributedWaitGroup) Add

func (wg *DistributedWaitGroup) Add(delta int) error

Add adds an expected number of works to wait on.

func (*DistributedWaitGroup) Done

func (wg *DistributedWaitGroup) Done() error

Done signals the parent that this workers has finished.

func (*DistributedWaitGroup) Wait

func (wg *DistributedWaitGroup) Wait() error

Wait will block until all workers have called Done().

WARNING: There aren't currently any guards in place to prevent other actors from calling Add() after the parent calls Wait(). This differs from the behavior of the sync.WaitGroup, which doesn't allow you to add workers after calling Wait(). So be careful...

type EtcdPubSubTopic

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

func NewPubSubTopic

func NewPubSubTopic(ctx context.Context, cid string, kapi etcdc.KeysAPI) (*EtcdPubSubTopic, error)

NewPubSubTopic uses Etcd as a pub/sub message broker. Not really the best application for Etcd, as the overhead of raft consensus is expensive. So don't expect to use this to send thousands of messages a second. I've only used it as a low volume message bus, in projects were I wanted to limit the number of technologies involved.

func NewPubSubTopicByKey

func NewPubSubTopicByKey(ctx context.Context, keyid string, ttl time.Duration, kapi etcdc.KeysAPI) (*EtcdPubSubTopic, error)

func (*EtcdPubSubTopic) Publish

func (t *EtcdPubSubTopic) Publish(msg []byte) error

func (*EtcdPubSubTopic) Subscribe

func (t *EtcdPubSubTopic) Subscribe() (<-chan *TopicMsg, error)

func (*EtcdPubSubTopic) UnSubscribe

func (t *EtcdPubSubTopic) UnSubscribe()

type Leadership

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

func NewLeaderElection

func NewLeaderElection(ctx context.Context, electionname string, kapi etcdc.KeysAPI) (l *Leadership, err error)

type NodeKeepAlive

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

func NewNodeKeepAlive

func NewNodeKeepAlive(nodeid string, nodettl time.Duration, kapi etcdc.KeysAPI) (*NodeKeepAlive, error)

func (*NodeKeepAlive) Stop

func (k *NodeKeepAlive) Stop()

type TopicMsg

type TopicMsg struct {
	Msg []byte
	Err error
}

type Topology

type Topology struct {
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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