118 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
# Docker Events Package
 | 
						|
 | 
						|
[](https://godoc.org/github.com/docker/go-events)
 | 
						|
[](https://circleci.com/gh/docker/go-events)
 | 
						|
 | 
						|
The Docker `events` package implements a composable event distribution package
 | 
						|
for Go.
 | 
						|
 | 
						|
Originally created to implement the [notifications in Docker Registry
 | 
						|
2](https://github.com/docker/distribution/blob/master/docs/notifications.md),
 | 
						|
we've found the pattern to be useful in other applications. This package is
 | 
						|
most of the same code with slightly updated interfaces. Much of the internals
 | 
						|
have been made available.
 | 
						|
 | 
						|
## Usage
 | 
						|
 | 
						|
The `events` package centers around a `Sink` type.  Events are written with
 | 
						|
calls to `Sink.Write(event Event)`. Sinks can be wired up in various
 | 
						|
configurations to achieve interesting behavior.
 | 
						|
 | 
						|
The canonical example is that employed by the
 | 
						|
[docker/distribution/notifications](https://godoc.org/github.com/docker/distribution/notifications)
 | 
						|
package. Let's say we have a type `httpSink` where we'd like to queue
 | 
						|
notifications. As a rule, it should send a single http request and return an
 | 
						|
error if it fails:
 | 
						|
 | 
						|
```go
 | 
						|
func (h *httpSink) Write(event Event) error {
 | 
						|
	p, err := json.Marshal(event)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	body := bytes.NewReader(p)
 | 
						|
	resp, err := h.client.Post(h.url, "application/json", body)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer resp.Body.Close()
 | 
						|
	
 | 
						|
	if resp.Status != 200 {
 | 
						|
		return errors.New("unexpected status")
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// implement (*httpSink).Close()
 | 
						|
```
 | 
						|
 | 
						|
With just that, we can start using components from this package. One can call
 | 
						|
`(*httpSink).Write` to send events as the body of a post request to a
 | 
						|
configured URL.
 | 
						|
 | 
						|
### Retries
 | 
						|
 | 
						|
HTTP can be unreliable. The first feature we'd like is to have some retry:
 | 
						|
 | 
						|
```go
 | 
						|
hs := newHTTPSink(/*...*/)
 | 
						|
retry := NewRetryingSink(hs, NewBreaker(5, time.Second))
 | 
						|
```
 | 
						|
 | 
						|
We now have a sink that will retry events against the `httpSink` until they
 | 
						|
succeed. The retry will backoff for one second after 5 consecutive failures
 | 
						|
using the breaker strategy.
 | 
						|
 | 
						|
### Queues
 | 
						|
 | 
						|
This isn't quite enough. We we want a sink that doesn't block while we are
 | 
						|
waiting for events to be sent. Let's add a `Queue`:
 | 
						|
 | 
						|
```go
 | 
						|
queue := NewQueue(retry)
 | 
						|
```
 | 
						|
 | 
						|
Now, we have an unbounded queue that will work through all events sent with
 | 
						|
`(*Queue).Write`. Events can be added asynchronously to the queue without
 | 
						|
blocking the current execution path. This is ideal for use in an http request.
 | 
						|
 | 
						|
### Broadcast
 | 
						|
 | 
						|
It usually turns out that you want to send to more than one listener. We can
 | 
						|
use `Broadcaster` to support this:
 | 
						|
 | 
						|
```go
 | 
						|
var broadcast = NewBroadcaster() // make it available somewhere in your application.
 | 
						|
broadcast.Add(queue) // add your queue!
 | 
						|
broadcast.Add(queue2) // and another!
 | 
						|
```
 | 
						|
 | 
						|
With the above, we can now call `broadcast.Write` in our http handlers and have
 | 
						|
all the events distributed to each queue. Because the events are queued, not
 | 
						|
listener blocks another.
 | 
						|
 | 
						|
### Extending
 | 
						|
 | 
						|
For the most part, the above is sufficient for a lot of applications. However,
 | 
						|
extending the above functionality can be done implementing your own `Sink`. The
 | 
						|
behavior and semantics of the sink can be completely dependent on the
 | 
						|
application requirements. The interface is provided below for reference:
 | 
						|
 | 
						|
```go
 | 
						|
type Sink {
 | 
						|
	Write(Event) error
 | 
						|
	Close() error
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
Application behavior can be controlled by how `Write` behaves. The examples
 | 
						|
above are designed to queue the message and return as quickly as possible.
 | 
						|
Other implementations may block until the event is committed to durable
 | 
						|
storage.
 | 
						|
 | 
						|
## Copyright and license
 | 
						|
 | 
						|
Copyright © 2016 Docker, Inc. go-events is licensed under the Apache License,
 | 
						|
Version 2.0. See [LICENSE](LICENSE) for the full license text.
 |