1 # Docker Events Package
3 [![GoDoc](https://godoc.org/github.com/docker/go-events?status.svg)](https://godoc.org/github.com/docker/go-events)
4 [![Circle CI](https://circleci.com/gh/docker/go-events.svg?style=shield)](https://circleci.com/gh/docker/go-events)
6 The Docker `events` package implements a composable event distribution package
9 Originally created to implement the [notifications in Docker Registry
10 2](https://github.com/docker/distribution/blob/master/docs/notifications.md),
11 we've found the pattern to be useful in other applications. This package is
12 most of the same code with slightly updated interfaces. Much of the internals
13 have been made available.
17 The `events` package centers around a `Sink` type. Events are written with
18 calls to `Sink.Write(event Event)`. Sinks can be wired up in various
19 configurations to achieve interesting behavior.
21 The canonical example is that employed by the
22 [docker/distribution/notifications](https://godoc.org/github.com/docker/distribution/notifications)
23 package. Let's say we have a type `httpSink` where we'd like to queue
24 notifications. As a rule, it should send a single http request and return an
28 func (h *httpSink) Write(event Event) error {
29 p, err := json.Marshal(event)
33 body := bytes.NewReader(p)
34 resp, err := h.client.Post(h.url, "application/json", body)
38 defer resp.Body.Close()
40 if resp.Status != 200 {
41 return errors.New("unexpected status")
47 // implement (*httpSink).Close()
50 With just that, we can start using components from this package. One can call
51 `(*httpSink).Write` to send events as the body of a post request to a
56 HTTP can be unreliable. The first feature we'd like is to have some retry:
59 hs := newHTTPSink(/*...*/)
60 retry := NewRetryingSink(hs, NewBreaker(5, time.Second))
63 We now have a sink that will retry events against the `httpSink` until they
64 succeed. The retry will backoff for one second after 5 consecutive failures
65 using the breaker strategy.
69 This isn't quite enough. We we want a sink that doesn't block while we are
70 waiting for events to be sent. Let's add a `Queue`:
73 queue := NewQueue(retry)
76 Now, we have an unbounded queue that will work through all events sent with
77 `(*Queue).Write`. Events can be added asynchronously to the queue without
78 blocking the current execution path. This is ideal for use in an http request.
82 It usually turns out that you want to send to more than one listener. We can
83 use `Broadcaster` to support this:
86 var broadcast = NewBroadcaster() // make it available somewhere in your application.
87 broadcast.Add(queue) // add your queue!
88 broadcast.Add(queue2) // and another!
91 With the above, we can now call `broadcast.Write` in our http handlers and have
92 all the events distributed to each queue. Because the events are queued, not
93 listener blocks another.
97 For the most part, the above is sufficient for a lot of applications. However,
98 extending the above functionality can be done implementing your own `Sink`. The
99 behavior and semantics of the sink can be completely dependent on the
100 application requirements. The interface is provided below for reference:
109 Application behavior can be controlled by how `Write` behaves. The examples
110 above are designed to queue the message and return as quickly as possible.
111 Other implementations may block until the event is committed to durable
114 ## Copyright and license
116 Copyright © 2016 Docker, Inc. go-events is licensed under the Apache License,
117 Version 2.0. See [LICENSE](LICENSE) for the full license text.