Categorygithub.com/docker/go-events
modulepackage
0.0.0-20241114183025-9940093291f5
Repository: https://github.com/docker/go-events.git
Documentation: pkg.go.dev

# README

Docker Events Package

GoDoc

The Docker events package implements a composable event distribution package for Go.

Originally created to implement the notifications in Docker Registry 2, 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 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:

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:

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:

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:

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:

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 for the full license text.

# Functions

NewBreaker returns a breaker that will backoff after the threshold has been tripped.
NewBroadcaster appends one or more sinks to the list of sinks.
NewChannel returns a channel.
NewExponentialBackoff returns an exponential backoff strategy with the desired config.
NewFilter returns a new filter that will send to events to dst that return true for Matcher.
NewQueue returns a queue to the provided Sink dst.
NewRetryingSink returns a sink that will retry writes to a sink, backing off on failure.

# Variables

DefaultExponentialBackoffConfig provides a default configuration for exponential backoff.
ErrSinkClosed is returned if a write is issued to a sink that has been closed.

# Structs

Breaker implements a circuit breaker retry strategy.
Broadcaster sends events to multiple, reliable Sinks.
Channel provides a sink that can be listened on.
ExponentialBackoff implements random backoff with exponentially increasing bounds as the number consecutive failures increase.
ExponentialBackoffConfig configures backoff parameters.
Filter provides an event sink that sends only events that are accepted by a Matcher.
Queue accepts all messages into a queue for asynchronous consumption by a sink.
RetryingSink retries the write until success or an ErrSinkClosed is returned.

# Interfaces

Event marks items that can be sent as events.
Matcher matches events.
RetryStrategy defines a strategy for retrying event sink writes.
Sink accepts and sends events.

# Type aliases

MatcherFunc implements matcher with just a function.