forked from TrueCloudLab/distribution
118 lines
3.7 KiB
Markdown
118 lines
3.7 KiB
Markdown
|
# Docker Events Package
|
||
|
|
||
|
[![GoDoc](https://godoc.org/github.com/docker/go-events?status.svg)](https://godoc.org/github.com/docker/go-events)
|
||
|
[![Circle CI](https://circleci.com/gh/docker/go-events.svg?style=shield)](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.
|