circuit

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 16, 2014 License: MIT Imports: 9 Imported by: 0

README

circuitbreaker

Circuitbreaker provides an easy way to use the Circuit Breaker pattern in a Go program.

Circuit breakers are typically used when your program makes remote calls. Remote calls can often hang for a while before they time out. If your application makes a lot of these requests, many resources can be tied up waiting for these time outs to occur. A circuit breaker wraps these remote calls and will trip after a defined amount of failures or time outs occur. When a circuit breaker is tripped any future calls will avoid making the remote call and return an error to the caller. In the meantime, the circuit breaker will periodically allow some calls to be tried again and will close the circuit if those are successful.

You can read more about this pattern and how it's used at:

GoDoc

Installation

  go get github.com/rubyist/circuitbreaker

Examples

Here is a quick example of what circuitbreaker provides

// Creates a circuit breaker that will trip if the function fails 10 times
cb := circuit.NewThresholdBreaker(10)

events := cb.Subscribe()
go func() {
  for {
    e := <-events
    // Monitor breaker events like BreakerTripped, BreakerReset, BreakerFail, BreakerReady
  }
}()

cb.Call(func() error {
	// This is where you'll do some remote call
	// If it fails, return an error
})

Circuitbreaker can also wrap a time out around the remote call.

// Creates a circuit breaker that will trip after 10 failures or time outs
// using a time out of 5 seconds
cb := circuit.NewTimeoutBreaker(Time.Second * 5, 10)

// Proceed as above

Circuitbreaker can also trip based on the number of failures in a given time period.

// Creates a circuit breaker that will trip if 10 failures occur in 1 minute
cb := circuit.NewFrequencyBreaker(time.Minute, 10)

// Proceed as above

Circuitbreaker also provides a wrapper around http.Client that will wrap a time out around any request.

// Passing in nil will create a regular http.Client.
// You can also build your own http.Client and pass it in
client := circuit.NewHTTPClient(time.Second * 5, 10, nil)

resp, err := client.Get("http://example.com/resource.json")

See the godoc for more examples.

Bugs, Issues, Feedback

Right here on GitHub: https://github.com/rubyist/circuitbreaker

Documentation

Overview

Package circuit implements the Circuit Breaker pattern. It will wrap a function call (typically one which uses remote services) and monitors for failures and/or time outs. When a threshold of failures or time outs has been reached, future calls to the function will not run. During this state, the breaker will periodically allow the function to run and, if it is successful, will start running the function again.

Circuit includes three types of circuit breakers:

A ThresholdBreaker will trip when the failure count reaches a given threshold. It does not matter how long it takes to reach the threshold.

A FrequencyBreaker will trip when the failure count reaches a given threshold within a given time period.

A TimeoutBreaker will trip when the failure count reaches a given threshold, with the added feature that the remote call taking longer than a given timeout will count as a failure.

Other types of circuit breakers can be easily built. Embedding a TrippableBreaker struct and providing the failure semantics with custom Fail() and Call() functions are all that is typically needed.

The package also provides a wrapper around an http.Client that wraps all of the http.Client functions with a Breaker.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrBreakerOpen    = errors.New("breaker open")
	ErrBreakerTimeout = errors.New("breaker time out")
)

Error codes returned by Call

Functions

This section is empty.

Types

type Breaker

type Breaker interface {
	Call(func() error) error
	Fail()
	Failures() int64
	Trip()
	Reset()
	Break()
	Ready() bool
	Tripped() bool
	Subscribe() <-chan BreakerEvent
}
Example (Events)
// This example demonstrates the BreakerTripped and BreakerReset callbacks. These are
// available on all breaker types.
breaker := NewThresholdBreaker(1)
events := breaker.Subscribe()

go func() {
	for {
		e := <-events
		switch e {
		case BreakerTripped:
			log.Println("breaker tripped")
		case BreakerReset:
			log.Println("breaker reset")
		case BreakerFail:
			log.Println("breaker fail")
		case BreakerReady:
			log.Println("breaker ready")
		}
	}
}()

breaker.Fail()
breaker.Reset()
Output:

func NoOp

func NoOp() Breaker

NoOp returns a Breaker null object. It implements the interface with no-ops for every function.

type BreakerEvent

type BreakerEvent int
const (
	BreakerTripped BreakerEvent = iota
	BreakerReset   BreakerEvent = iota
	BreakerFail    BreakerEvent = iota
	BreakerReady   BreakerEvent = iota
)

type FrequencyBreaker

type FrequencyBreaker struct {
	// Duration is the amount of time in which the failure theshold must be met.
	Duration time.Duration

	// Threshold is the number of failures Breaker will allow before tripping
	Threshold int64

	*TrippableBreaker
	// contains filtered or unexported fields
}

FrequencyBreaker is a circuit breaker that will only trip if the threshold is met within a certain amount of time.

Example
// This example sets up a FrequencyBreaker that will trip if remoteCall returns
// an error 10 times in a row within a period of 2 minutes.
breaker := NewFrequencyBreaker(time.Minute*2, 10)
err := breaker.Call(remoteCall)
if err != nil {
	log.Fatal(err)
}
Output:

func NewFrequencyBreaker

func NewFrequencyBreaker(duration time.Duration, threshold int64) *FrequencyBreaker

NewFrequencyBreaker returns a new FrequencyBreaker with the given duration and failure threshold. If a duration is specified as 0 then no duration will be used and the behavior will be the same as a ThresholdBreaker

func (*FrequencyBreaker) Call

func (cb *FrequencyBreaker) Call(circuit func() error) error

Call wraps the function the FrequencyBreaker will protect. A failure is recorded whenever the function returns an error. If the threshold is met within the duration, the FrequencyBreaker will trip.

func (*FrequencyBreaker) Fail

func (cb *FrequencyBreaker) Fail()

Fail records a failure. If the failure count meets the threshold within the duration, the circuit breaker will trip. If a BreakerTripped callback is available it will be run.

func (*FrequencyBreaker) Failures

func (cb *FrequencyBreaker) Failures() int64

Failures returns the number of failures for this circuit breaker. The failure count for a FrequencyBreaker resets when the duration expires.

type HTTPClient

type HTTPClient struct {
	Client         *http.Client
	BreakerTripped func()
	BreakerReset   func()
	BreakerLookup  func(*HTTPClient, interface{}) Breaker
	Panel          *Panel
}

HTTPClient is a wrapper around http.Client that provides circuit breaker capabilities.

By default, the client will use its defaultBreaker. A BreakerLookup function may be provided to allow different breakers to be used based on the circumstance. See the implementation of NewHostBasedHTTPClient for an example of this.

Example
// This example sets up an HTTP client wrapped in a TimeoutBreaker. The breaker
// will trip with the same behavior as TimeoutBreaker.
client := NewHTTPClient(time.Second*5, 10, nil)

resp, err := client.Get("http://example.com/resource.json")
if err != nil {
	log.Fatal(err)
}
resource, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
	log.Fatal(err)
}
fmt.Printf("%s", resource)
Output:

func NewHTTPClient

func NewHTTPClient(timeout time.Duration, threshold int64, client *http.Client) *HTTPClient

NewHTTPClient provides a circuit breaker wrapper around http.Client. It wraps all of the regular http.Client functions. Specifying 0 for timeout will give a breaker that does not check for time outs.

func NewHTTPClientWithBreaker

func NewHTTPClientWithBreaker(breaker Breaker, client *http.Client) *HTTPClient

NewHTTPClientWithBreaker provides a circuit breaker wrapper around http.Client. It wraps all of the regular http.Client functions using the provided Breaker.

func NewHostBasedHTTPClient

func NewHostBasedHTTPClient(timeout time.Duration, threshold int64, client *http.Client) *HTTPClient

NewHostBasedHTTPClient provides a circuit breaker wrapper around http.Client. This client will use one circuit breaker per host parsed from the request URL. This allows you to use a single HTTPClient for multiple hosts with one host's breaker not affecting the other hosts.

func (*HTTPClient) Do

func (c *HTTPClient) Do(req *http.Request) (*http.Response, error)

Do wraps http.Client Do()

func (*HTTPClient) Get

func (c *HTTPClient) Get(url string) (*http.Response, error)

Get wraps http.Client Get()

func (*HTTPClient) Head

func (c *HTTPClient) Head(url string) (*http.Response, error)

Head wraps http.Client Head()

func (*HTTPClient) Post

func (c *HTTPClient) Post(url string, bodyType string, body io.Reader) (*http.Response, error)

Post wraps http.Client Post()

func (*HTTPClient) PostForm

func (c *HTTPClient) PostForm(url string, data url.Values) (*http.Response, error)

PostForm wraps http.Client PostForm()

type Panel

type Panel struct {
	Statter      Statter
	StatsPrefixf string
	// contains filtered or unexported fields
}

Panel tracks a group of circuit breakers by name.

Example
// This example demonstrates using a Panel to aggregate and manage circuit breakers.
breaker1 := NewThresholdBreaker(10)
breaker2 := NewFrequencyBreaker(time.Minute, 10)

panel := NewPanel()
panel.Add("breaker1", breaker1)
panel.Add("breaker2", breaker2)

// Elsewhere in the code ...
b1, _ := panel.Get("breaker1")
b1.Call(func() error {
	// Do some work
	return nil
})

b2, _ := panel.Get("breaker2")
b2.Call(func() error {
	// Do some work
	return nil
})
Output:

Example (Stats)
// This example demonstrates how to push circuit breaker stats to statsd via a Panel.
// This example uses g2s. Anything conforming to the Statter interface can be used.
s, err := g2s.Dial("udp", "statsd-server:8125")
if err != nil {
	log.Fatal(err)
}

breaker := NewThresholdBreaker(10)
panel := NewPanel()
panel.Statter = s
panel.StatsPrefixf = "sys.production"
panel.Add("x", breaker)

breaker.Trip()  // sys.production.circuit.x.tripped
breaker.Reset() // sys.production.circuit.x.reset, sys.production.circuit.x.trip-time
breaker.Fail()  // sys.production.circuit.x.fail
breaker.Ready() // sys.production.circuit.x.ready (if it's tripped and ready to retry)
Output:

func NewPanel

func NewPanel() *Panel

func (*Panel) Add

func (p *Panel) Add(name string, cb Breaker)

Add sets the name as a reference to the given circuit breaker.

func (*Panel) Get

func (p *Panel) Get(name string) (Breaker, bool)

Get retrieves a circuit breaker by name. If no circuit breaker exists, it returns the NoOp one and sets ok to false.

func (*Panel) Subscribe

func (p *Panel) Subscribe() <-chan PanelEvent

Subscribe returns a channel of PanelEvents. Whenever a breaker changes state, the PanelEvent will be sent over the channel. See BreakerEvent for the types of events.

type PanelEvent

type PanelEvent struct {
	Name  string
	Event BreakerEvent
}

type Statter

type Statter interface {
	Counter(sampleRate float32, bucket string, n ...int)
	Timing(sampleRate float32, bucket string, d ...time.Duration)
	Gauge(sampleRate float32, bucket string, value ...string)
}

type ThresholdBreaker

type ThresholdBreaker struct {
	*FrequencyBreaker
}

ThresholdBreaker is a circuit breaker that will trip when its failure count passes a given threshold. Clients of ThresholdBreaker can either manually call the Fail function to record a failure, checking the tripped state themselves, or they can use the Call function to wrap the ThresholdBreaker around a function call.

Example
// This example sets up a ThresholdBreaker that will trip if remoteCall returns
// an error 10 times in a row. The error returned by Call() will be the error
// returned by remoteCall, unless the breaker has been tripped, in which case
// it will return ErrBreakerOpen.
breaker := NewThresholdBreaker(10)
err := breaker.Call(remoteCall)
if err != nil {
	log.Fatal(err)
}
Output:

Example (Manual)
// This example demonstrates the manual use of a ThresholdBreaker. The breaker
// will trip when Fail is called 10 times in a row.
breaker := NewThresholdBreaker(10)
if breaker.Ready() {
	err := remoteCall
	if err != nil {
		breaker.Fail()
		log.Fatal(err)
	} else {
		breaker.Reset()
	}
}
Output:

func NewThresholdBreaker

func NewThresholdBreaker(threshold int64) *ThresholdBreaker

NewThresholdBreaker creates a new ThresholdBreaker with the given failure threshold.

type TimeoutBreaker

type TimeoutBreaker struct {
	// Timeout is the length of time the Breaker will wait for Call() to finish
	Timeout time.Duration
	*ThresholdBreaker
}

TimeoutBreaker is a ThresholdBreaker that will record a failure if the function it is protecting takes too long to run. Clients of Timeout must use the Call function. The Fail function is a noop.

Example
// This example sets up a TimeoutBreaker that will trip if remoteCall returns
// an error OR takes longer than one second 10 times in a row. The error returned
// by Call() will be the error returned by remoteCall with two exceptions: if
// remoteCall takes longer than one second the return value will be ErrBreakerTimeout,
// if the breaker has been tripped the return value will be ErrBreakerOpen.
breaker := NewTimeoutBreaker(time.Second, 10)
err := breaker.Call(remoteCall)
if err != nil {
	log.Fatal(err)
}
Output:

func NewTimeoutBreaker

func NewTimeoutBreaker(timeout time.Duration, threshold int64) *TimeoutBreaker

NewTimeoutBreaker returns a new TimeoutBreaker with the given call timeout and failure threshold. If timeout is specified as 0 then no timeout will be used and the behavior will be the same as a ThresholdBreaker

func (*TimeoutBreaker) Call

func (cb *TimeoutBreaker) Call(circuit func() error) error

Call wraps the function the TimeoutBreaker will protect. A failure is recorded whenever the function returns an error. If the threshold is met, the TimeoutBreaker will trip.

func (*TimeoutBreaker) Fail

func (cb *TimeoutBreaker) Fail()

Fail is a noop for a TimeoutBreaker. Clients must use Call()

type TrippableBreaker

type TrippableBreaker struct {
	// ResetTimeout is the minimum amount of time the Breaker will wait
	// before allowing the function to be called again
	ResetTimeout time.Duration
	// contains filtered or unexported fields
}

TrippableBreaker is a base for building trippable circuit breakers. It keeps track of the tripped state and runs the OnTrip and OnReset callbacks.

func NewTrippableBreaker

func NewTrippableBreaker(resetTimeout time.Duration) *TrippableBreaker

NewResettingBreaker returns a new ResettingBreaker with the given reset timeout

func (*TrippableBreaker) Break

func (cb *TrippableBreaker) Break()

Break trips the circuit breaker and prevents it from auto resetting. Use this when manual control over the circuit breaker state is needed.

func (*TrippableBreaker) Call

func (cb *TrippableBreaker) Call(circuit func() error) error

Call runs the given function. No wrapping is performed.

func (*TrippableBreaker) Fail

func (cb *TrippableBreaker) Fail()

Fail records the time of a failure

func (*TrippableBreaker) Failures

func (cb *TrippableBreaker) Failures() int64

Failures returns the number of failures for this circuit breaker.

func (*TrippableBreaker) Ready

func (cb *TrippableBreaker) Ready() bool

Ready will return true if the circuit breaker is ready to call the function. It will be ready if the breaker is in a reset state, or if it is time to retry the call for auto resetting.

func (*TrippableBreaker) Reset

func (cb *TrippableBreaker) Reset()

Reset will reset the circuit breaker. After Reset() is called, Tripped() will return false. If an OnReset callback is available it will be run.

func (*TrippableBreaker) Subscribe

func (cb *TrippableBreaker) Subscribe() <-chan BreakerEvent

Subscribe returns a channel of BreakerEvents. Whenever the breaker changes state, the state will be sent over the channel. See BreakerEvent for the types of events.

func (*TrippableBreaker) Trip

func (cb *TrippableBreaker) Trip()

Trip will trip the circuit breaker. After Trip() is called, Tripped() will return true. If an OnTrip callback is available it will be run.

func (*TrippableBreaker) Tripped

func (cb *TrippableBreaker) Tripped() bool

Tripped returns true if the circuit breaker is tripped, false if it is reset.

Jump to

Keyboard shortcuts

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