circuitbreaker

package
v0.0.0-...-57f3b98 Latest Latest
Warning

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

Go to latest
Published: May 16, 2024 License: BSD-3-Clause Imports: 6 Imported by: 0

Documentation

Overview

Package circuitbreaker is an in-memory implementation of circuit breaker. The idea is that each local node (server) should maintain it's own knowledge of the service availability, instead of depending on external infrastructure like distributed cache.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrBrokenCircuit   = errors.New("circuit-breaker: broken")
	ErrIsolatedCircuit = errors.New("circuit-breaker: isolated")
)

Functions

func Ratio

func Ratio[T constraints.Integer](n, total T) float64

Types

type CircuitBreaker

type CircuitBreaker struct {
	OnStateChanged func(ctx context.Context, from, to Status)
	// contains filtered or unexported fields
}
Example
opt := circuitbreaker.NewOption()
opt.BreakDuration = 100 * time.Millisecond
opt.SamplingDuration = 1 * time.Second

cb := circuitbreaker.New(opt)
cb.OnStateChanged = func(ctx context.Context, from, to circuitbreaker.Status) {
	fmt.Printf("status changed from %s to %s\n", from, to)
}

key := "key"
fmt.Println("initial status:")
fmt.Println(cb.Status(ctx, key))

// Opens after failure ratio exceeded.
for i := 0; i <= int(opt.FailureThreshold+1); i++ {
	_ = cb.Do(ctx, key, func() error {
		return errors.New("foo")
	})
}

// Break duration.
time.Sleep(105 * time.Millisecond)

// Recover.
for i := 0; i <= int(opt.SuccessThreshold+1); i++ {
	_ = cb.Do(ctx, key, func() error {
		return nil
	})
}
Output:

initial status:
closed <nil>
status changed from closed to open
status changed from open to half-open
status changed from half-open to closed

func New

func New(opt *Option) *CircuitBreaker

func (*CircuitBreaker) Do

func (c *CircuitBreaker) Do(ctx context.Context, key string, fn func() error) error

func (*CircuitBreaker) ResetIn

func (c *CircuitBreaker) ResetIn(ctx context.Context, key string) time.Duration

func (*CircuitBreaker) Status

func (c *CircuitBreaker) Status(ctx context.Context, key string) (Status, error)

type ClosedState

type ClosedState struct {
	SamplingDuration time.Duration
	FailureThreshold int
	FailureRatio     float64
	Now              func() time.Time
}

Each state holds an option.

func (*ClosedState) Do

func (c *ClosedState) Do(s *State, fn func() error) error

func (*ClosedState) Entry

func (c *ClosedState) Entry() *State

func (*ClosedState) Next

func (c *ClosedState) Next(s *State) (Status, bool)

type HalfOpenState

type HalfOpenState struct {
	SuccessThreshold int
}

func (*HalfOpenState) Do

func (h *HalfOpenState) Do(s *State, fn func() error) error

func (*HalfOpenState) Entry

func (h *HalfOpenState) Entry() *State

func (*HalfOpenState) Next

func (h *HalfOpenState) Next(s *State) (Status, bool)

type InMemory

type InMemory struct {
	// contains filtered or unexported fields
}

func NewInMemory

func NewInMemory() *InMemory

func (*InMemory) Get

func (i *InMemory) Get(ctx context.Context, key string) (*State, error)

func (*InMemory) Set

func (i *InMemory) Set(ctx context.Context, key string, res *State) error

type IsolatedState

type IsolatedState struct {
}

func NewIsolatedState

func NewIsolatedState() *IsolatedState

func (*IsolatedState) Do

func (i *IsolatedState) Do(s *State, fn func() error) error

func (*IsolatedState) Entry

func (s *IsolatedState) Entry() *State

func (*IsolatedState) Next

func (i *IsolatedState) Next(s *State) (Status, bool)

type OpenState

type OpenState struct {
	BreakDuration time.Duration
	Now           func() time.Time
}

func (*OpenState) Do

func (o *OpenState) Do(_ *State, fn func() error) error

func (*OpenState) Entry

func (o *OpenState) Entry() *State

func (*OpenState) Next

func (o *OpenState) Next(s *State) (Status, bool)

type Option

type Option struct {
	SuccessThreshold int
	FailureThreshold int
	BreakDuration    time.Duration
	Now              func() time.Time
	FailureRatio     float64
	SamplingDuration time.Duration
	Store            store
}

func NewOption

func NewOption() *Option

type RoundTripper

type RoundTripper struct {
	KeyFromRequest func(*http.Request) string
	// contains filtered or unexported fields
}
Example
opt := circuitbreaker.NewOption()
opt.BreakDuration = 100 * time.Millisecond
opt.SamplingDuration = 1 * time.Second
cb := circuitbreaker.New(opt)
cb.OnStateChanged = func(ctx context.Context, from, to circuitbreaker.Status) {
	fmt.Printf("status changed from %s to %s\n", from, to)
}

key := "key"
fmt.Println("initial status:")
fmt.Println(cb.Status(ctx, key))

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusInternalServerError)
}))
defer ts.Close()

client := ts.Client()
client.Transport = circuitbreaker.NewRoundTripper(client.Transport, cb)

re := regexp.MustCompile(`\d{5}`)
// Opens after failure ratio exceeded.
for i := 0; i < int(opt.FailureThreshold)+1; i++ {
	_, err := client.Get(ts.URL)
	if err != nil {
		// Replace port since it changes dynamically and breaks the test.
		msg := re.ReplaceAllString(err.Error(), "8080")
		fmt.Println(msg)
		continue
	}
}
Output:

initial status:
closed <nil>
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
Get "http://127.0.0.1:8080": 500 Internal Server Error
status changed from closed to open
Get "http://127.0.0.1:8080": circuit-breaker: broken

func NewRoundTripper

func NewRoundTripper(t transporter, cb breaker) *RoundTripper

func (*RoundTripper) RoundTrip

func (t *RoundTripper) RoundTrip(r *http.Request) (resp *http.Response, err error)

type State

type State struct {
	Status  Status // New status
	Count   int    // success or failure count.
	Total   int
	CloseAt time.Time
	ResetAt time.Time
	// contains filtered or unexported fields
}

type Status

type Status int
const (
	Closed Status = iota
	Open
	HalfOpen
	Isolated
)

func (Status) String

func (s Status) String() string

Jump to

Keyboard shortcuts

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