Documentation ¶
Overview ¶
Package circuit is a Go implementation of the circuit breaker pattern. Most documentation is available on the GitHub README page https://github.com/cep21/circuit/blob/master/README.md
Use case ¶
Netflix describes most use cases on their wiki for Hystrix at https://github.com/Netflix/Hystrix/wiki. Quoting the wiki:
Give protection from and control over latency and failure from dependencies accessed (typically over the network) via third-party client libraries. Stop cascading failures in a complex distributed system. Fail fast and rapidly recover. Fallback and gracefully degrade when possible. Enable near real-time monitoring, alerting, and operational control.
It is a great library for microservice applications that require a large number of calls to many, small services where any one of these calls could fail, or any of these services could be down or degraded.
Getting started ¶
The godoc contains many examples. Look at them for a good start on how to get started integrated and using the Hystrix library for Go.
Circuit Flowchart ¶
A circuits start Closed. The default logic is to open a circuit if more than 20 requests have come in during a 10-second window, and over 50% of requests during that 10-second window are failing.
Once failed, the circuit waits 10 seconds before allowing a single request. If that request succeeds, then the circuit closes. If it fails, then the circuit waits another 10 seconds before allowing another request (and so on).
Almost every part of this flow can be configured. See the CommandProperties struct for information.
Metric tracking ¶
All circuits record circuit stats that you can fetch out of the Circuit at any time. In addition, you can also inject your own circuit stat trackers by modifying the MetricsCollectors structure.
Example (Http) ¶
This is a full example of using a circuit around HTTP requests.
h := circuit.Manager{} c := h.MustCreateCircuit("hello-http", circuit.Config{ Execution: circuit.ExecutionConfig{ // Timeout after 3 seconds Timeout: time.Second * 3, }, }) testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { _, _ = io.WriteString(rw, "hello world") })) defer testServer.Close() var body bytes.Buffer runErr := c.Run(context.Background(), func(ctx context.Context) error { req, err := http.NewRequest("GET", testServer.URL, nil) if err != nil { return circuit.SimpleBadRequest{Err: err} } req = req.WithContext(ctx) resp, err := http.DefaultClient.Do(req) if err != nil { return err } if resp.StatusCode >= 400 && resp.StatusCode <= 499 { return circuit.SimpleBadRequest{Err: errors.New("server found your request invalid")} } if resp.StatusCode < 200 || resp.StatusCode > 299 { return fmt.Errorf("invalid status code: %d", resp.StatusCode) } if _, err := io.Copy(&body, resp.Body); err != nil { return err } return resp.Body.Close() }) if runErr == nil { fmt.Printf("We saw a body\n") return } fmt.Printf("There was an error with the request: %s\n", runErr)
Output: We saw a body
Index ¶
- func IsBadRequest(err error) bool
- type BadRequest
- type Circuit
- func (c *Circuit) CloseCircuit(ctx context.Context)
- func (c *Circuit) ConcurrentCommands() int64
- func (c *Circuit) ConcurrentFallbacks() int64
- func (c *Circuit) Config() Config
- func (c *Circuit) Execute(ctx context.Context, runFunc func(context.Context) error, ...) error
- func (c *Circuit) Go(ctx context.Context, runFunc func(context.Context) error, ...) error
- func (c *Circuit) IsOpen() bool
- func (c *Circuit) Name() string
- func (c *Circuit) OpenCircuit(ctx context.Context)
- func (c *Circuit) Run(ctx context.Context, runFunc func(context.Context) error) error
- func (c *Circuit) SetConfigNotThreadSafe(config Config)
- func (c *Circuit) SetConfigThreadSafe(config Config)
- func (c *Circuit) Var() expvar.Var
- type ClosedToOpen
- type CommandPropertiesConstructor
- type Config
- type Configurable
- type Error
- type ExecutionConfig
- type FallbackConfig
- type FallbackMetrics
- type FallbackMetricsCollection
- func (r FallbackMetricsCollection) ErrConcurrencyLimitReject(ctx context.Context, now time.Time)
- func (r FallbackMetricsCollection) ErrFailure(ctx context.Context, now time.Time, duration time.Duration)
- func (r FallbackMetricsCollection) Success(ctx context.Context, now time.Time, duration time.Duration)
- func (r FallbackMetricsCollection) Var() expvar.Var
- type GeneralConfig
- type Manager
- type Metrics
- type MetricsCollection
- type MetricsCollectors
- type OpenToClosed
- type RunMetrics
- type RunMetricsCollection
- func (r RunMetricsCollection) ErrBadRequest(ctx context.Context, now time.Time, duration time.Duration)
- func (r RunMetricsCollection) ErrConcurrencyLimitReject(ctx context.Context, now time.Time)
- func (r RunMetricsCollection) ErrFailure(ctx context.Context, now time.Time, duration time.Duration)
- func (r RunMetricsCollection) ErrInterrupt(ctx context.Context, now time.Time, duration time.Duration)
- func (r RunMetricsCollection) ErrShortCircuit(ctx context.Context, now time.Time)
- func (r RunMetricsCollection) ErrTimeout(ctx context.Context, now time.Time, duration time.Duration)
- func (r RunMetricsCollection) Success(ctx context.Context, now time.Time, duration time.Duration)
- func (r RunMetricsCollection) Var() expvar.Var
- type SimpleBadRequest
- type TimeKeeper
Examples ¶
- Package (Http)
- BadRequest
- Circuit (Noearlyterminate)
- Circuit.Execute (Fallback)
- Circuit.Execute (Fallbackhelloworld)
- Circuit.Execute (Helloworld)
- Circuit.Execute (Panics)
- Circuit.Go
- Circuit.Go (Panics)
- Circuit.SetConfigThreadSafe
- CommandPropertiesConstructor
- Config (Custommetrics)
- Error (Checking)
- Manager.MustCreateCircuit (Helloworld)
- Manager.Var
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsBadRequest ¶
IsBadRequest returns true if the error is of type BadRequest
Types ¶
type BadRequest ¶
type BadRequest interface {
BadRequest() bool
}
BadRequest is implemented by an error returned by runFunc if you want to consider the requestor bad, not the circuit bad. See http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/exception/HystrixBadRequestException.html and https://github.com/Netflix/Hystrix/wiki/How-To-Use#error-propagation for information.
Example ¶
This example shows how to return errors in a circuit without considering the circuit at fault. Here, even if someone tries to divide by zero, the circuit will not consider it a failure even if the function returns non nil error.
c := circuit.NewCircuitFromConfig("divider", circuit.Config{}) divideInCircuit := func(numerator, denominator int) (int, error) { var result int err := c.Run(context.Background(), func(ctx context.Context) error { if denominator == 0 { // This error type is not counted as a failure of the circuit return &circuit.SimpleBadRequest{ Err: errors.New("someone tried to divide by zero"), } } result = numerator / denominator return nil }) return result, err } _, err := divideInCircuit(10, 0) fmt.Println("Result of 10/0 is", err)
Output: Result of 10/0 is someone tried to divide by zero
type Circuit ¶
type Circuit struct { // circuitStats CmdMetricCollector RunMetricsCollection FallbackMetricCollector FallbackMetricsCollection CircuitMetricsCollector MetricsCollection // ClosedToOpen controls when to open a closed circuit ClosedToOpen ClosedToOpen // openToClosed controls when to close an open circuit OpenToClose OpenToClosed // contains filtered or unexported fields }
Circuit is a circuit breaker pattern implementation that can accept commands and open/close on failures
Example (Noearlyterminate) ¶
If the context passed into a circuit function ends, before the circuit can finish, it does not count the circuit as unhealthy. You can disable this behavior with the `IgnoreInterrupts` flag.
This example proves that terminating a circuit call early because the passed in context died does not, by default, count as an error on the circuit. It also demonstrates setting up internal stat collection by default for all circuits
// Inject stat collection to prove these failures don't count f := rolling.StatFactory{} manager := circuit.Manager{ DefaultCircuitProperties: []circuit.CommandPropertiesConstructor{ f.CreateConfig, }, } c := manager.MustCreateCircuit("don't fail me bro") // The passed in context times out in one millisecond ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond) defer cancel() errResult := c.Execute(ctx, func(ctx context.Context) error { select { case <-ctx.Done(): // This will return early, with an error, since the parent context was canceled after 1 ms return ctx.Err() case <-time.After(time.Hour): panic("We never actually get this far") } }, nil) rs := f.RunStats("don't fail me bro") fmt.Println("errResult is", errResult) fmt.Println("The error and timeout count is", rs.ErrTimeouts.TotalSum()+rs.ErrFailures.TotalSum())
Output: errResult is context deadline exceeded The error and timeout count is 0
func NewCircuitFromConfig ¶
NewCircuitFromConfig creates an inline circuit. If you want to group all your circuits together, you should probably just use Manager struct instead.
func (*Circuit) CloseCircuit ¶
CloseCircuit closes an open circuit. Usually because we think it's healthy again. Be aware, if the circuit isn't actually healthy, it will just open back up again.
func (*Circuit) ConcurrentCommands ¶
ConcurrentCommands returns how many commands are currently running
func (*Circuit) ConcurrentFallbacks ¶
ConcurrentFallbacks returns how many fallbacks are currently running
func (*Circuit) Config ¶
Config returns the circuit's configuration. Modifications to this configuration are not reflected by the circuit. In other words, this creates a copy.
func (*Circuit) Execute ¶
func (c *Circuit) Execute(ctx context.Context, runFunc func(context.Context) error, fallbackFunc func(context.Context, error) error) error
Execute the circuit. Prefer this over Go. Similar to http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/HystrixCommand.html#execute-- The returned error will either be the result of runFunc, the result of fallbackFunc, or an internal library error. Internal library errors will match the interface Error and you can use type casting to check this.
Example (Fallback) ¶
This example shows execute failing (marking the circuit with a failure), but not returning an error back to the user since the fallback was able to execute. For this case, we try to load the size of the largest message a user can send, but fall back to 140 if the load fails.
c := circuit.NewCircuitFromConfig("divider", circuit.Config{}) var maximumMessageSize int err := c.Execute(context.Background(), func(_ context.Context) error { return errors.New("your circuit failed") }, func(ctx context.Context, err2 error) error { maximumMessageSize = 140 return nil }) fmt.Printf("value=%d err=%v", maximumMessageSize, err)
Output: value=140 err=<nil>
Example (Fallbackhelloworld) ¶
This example shows how fallbacks execute to return alternate errors or provide logic when the circuit is open.
// You can create circuits without using the manager c := circuit.NewCircuitFromConfig("hello-world-fallback", circuit.Config{}) errResult := c.Execute(context.Background(), func(ctx context.Context) error { return errors.New("this will fail") }, func(ctx context.Context, err error) error { fmt.Println("Circuit failed with error, but fallback returns nil") return nil }) fmt.Println("Execution result:", errResult)
Output: Circuit failed with error, but fallback returns nil Execution result: <nil>
Example (Helloworld) ¶
This example shows execute failing (marking the circuit with a failure), but not returning an error back to the user since the fallback was able to execute. For this case, we try to load the size of the largest message a user can send, but fall back to 140 if the load fails.
c := circuit.NewCircuitFromConfig("hello-world", circuit.Config{}) err := c.Execute(context.Background(), func(_ context.Context) error { return nil }, nil) fmt.Printf("err=%v", err)
Output: err=<nil>
Example (Panics) ¶
Code executed with `Execute` does not spawn a goroutine and panics naturally go up the call stack to the caller. This is also true for `Go`, where we attempt to recover and throw panics on the same stack that calls Go. This example will panic, and the panic can be caught up the stack.
h := circuit.Manager{} c := h.MustCreateCircuit("panic_up") defer func() { r := recover() if r != nil { fmt.Println("I recovered from a panic", r) } }() _ = c.Execute(context.Background(), func(ctx context.Context) error { panic("oh no") }, nil)
Output: I recovered from a panic oh no
func (*Circuit) Go ¶
func (c *Circuit) Go(ctx context.Context, runFunc func(context.Context) error, fallbackFunc func(context.Context, error) error) error
Go executes `Execute`, but uses spawned goroutines to end early if the context is canceled. Use this if you don't trust the runFunc to end correctly if context fails. This is a design mirroed in the go-hystrix library, but be warned it is very dangerous and could leave orphaned goroutines hanging around forever doing who knows what.
Example ¶
It is recommended to use `circuit.Execute` and a context aware function. If, however, you want to exit your run function early and leave it hanging (possibly forever), then you can call `circuit.Go`.
h := circuit.Manager{} c := h.MustCreateCircuit("untrusting-circuit", circuit.Config{ Execution: circuit.ExecutionConfig{ // Time out the context after a few ms Timeout: time.Millisecond * 30, }, }) errResult := c.Go(context.Background(), func(ctx context.Context) error { // Sleep 30 seconds, way longer than our timeout time.Sleep(time.Second * 30) return nil }, nil) fmt.Printf("err=%v", errResult)
Output: err=context deadline exceeded
Example (Panics) ¶
Even though Go executes inside a goroutine, we catch that panic and bubble it up the same call stack that called Go
c := circuit.NewCircuitFromConfig("panic_up", circuit.Config{}) defer func() { r := recover() if r != nil { fmt.Println("I recovered from a panic", r) } }() _ = c.Go(context.Background(), func(ctx context.Context) error { panic("oh no") }, nil)
Output: I recovered from a panic oh no
func (*Circuit) IsOpen ¶
IsOpen returns true if the circuit should be considered 'open' (ie not allowing runFunc calls)
func (*Circuit) OpenCircuit ¶
OpenCircuit will open a closed circuit. The circuit will then try to repair itself
func (*Circuit) Run ¶
Run will execute the circuit without a fallback. It is the equivalent of calling Execute with a nil fallback function
func (*Circuit) SetConfigNotThreadSafe ¶
SetConfigNotThreadSafe is only useful during construction before a circuit is being used. It is not thread safe, but will modify all the circuit's internal structs to match what the config wants. It also doe *NOT* use the default configuration parameters.
func (*Circuit) SetConfigThreadSafe ¶
SetConfigThreadSafe changes the current configuration of this circuit. Note that many config parameters, specifically those around creating stat tracking buckets, are not modifiable during runtime for efficiency reasons. Those buckets will stay the same.
Example ¶
Many configuration variables can be set at runtime in a thread safe way
h := circuit.Manager{} c := h.MustCreateCircuit("changes-at-runtime", circuit.Config{}) // ... later on (during live) c.SetConfigThreadSafe(circuit.Config{ Execution: circuit.ExecutionConfig{ MaxConcurrentRequests: int64(12), }, })
Output:
type ClosedToOpen ¶
type ClosedToOpen interface { RunMetrics Metrics // ShouldOpen will attempt to open a circuit that is currently closed, after a bad request comes in. Only called // after bad requests, never called after a successful request ShouldOpen(ctx context.Context, now time.Time) bool // Prevent a single request from going through while the circuit is closed. // Even though the circuit is closed, and we want to allow the circuit to remain closed, we still prevent this // command from happening. The error will return as a short circuit to the caller, as well as trigger fallback // logic. This could be useful if your circuit is closed, but some external force wants you to pretend to be open. Prevent(ctx context.Context, now time.Time) bool }
ClosedToOpen receives events and controls if the circuit should open or close as a result of those events. Return true if the circuit should open, false if the circuit should close.
type CommandPropertiesConstructor ¶
CommandPropertiesConstructor is a generic function that can create command properties to configure a circuit by name It is safe to leave not configured properties their empty value.
Example ¶
You can use DefaultCircuitProperties to set configuration dynamically for any circuit
myFactory := func(circuitName string) circuit.Config { timeoutsByName := map[string]time.Duration{ "v1": time.Second, "v2": time.Second * 2, } customTimeout := timeoutsByName[circuitName] if customTimeout == 0 { // Just return empty if you don't want to set any config return circuit.Config{} } return circuit.Config{ Execution: circuit.ExecutionConfig{ Timeout: customTimeout, }, } } // Manager manages circuits with unique names h := circuit.Manager{ DefaultCircuitProperties: []circuit.CommandPropertiesConstructor{myFactory}, } h.MustCreateCircuit("v1") fmt.Println("The timeout of v1 is", h.GetCircuit("v1").Config().Execution.Timeout)
Output: The timeout of v1 is 1s
type Config ¶
type Config struct { General GeneralConfig Execution ExecutionConfig Fallback FallbackConfig Metrics MetricsCollectors }
Config controls how a circuit operates
Example (Custommetrics) ¶
Implement interfaces CmdMetricCollector or FallbackMetricCollector to know what happens with commands or fallbacks.
Then pass those implementations to configure.
config := circuit.Config{ Metrics: circuit.MetricsCollectors{ Run: []circuit.RunMetrics{ // Here is where I would insert my custom metric collector }, }, } circuit.NewCircuitFromConfig("custom-metrics", config)
Output:
type Configurable ¶
type Configurable interface { // SetConfigThreadSafe can be called while the circuit is currently being used and will modify things that are // safe to change live. SetConfigThreadSafe(props Config) // SetConfigNotThreadSafe should only be called when the circuit is not in use: otherwise it will fail -race // detection SetConfigNotThreadSafe(props Config) }
Configurable is anything that can receive configuration changes while live
type Error ¶
type Error interface { error // ConcurrencyLimitReached returns true if this error is because the concurrency limit has been reached. ConcurrencyLimitReached() bool // CircuitOpen returns true if this error is because the circuit is open. CircuitOpen() bool }
Error is the type of error returned by internal errors using the circuit library.
Example (Checking) ¶
Shows how to check if an error is part of the circuit library.
x := errors.New("an error") if _, ok := x.(circuit.Error); ok { fmt.Println("this error is a circuit library error, not the result of runFunc or fallbackFunc") }
Output:
type ExecutionConfig ¶
type ExecutionConfig struct { // ExecutionTimeout is https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.thread.timeoutInMilliseconds Timeout time.Duration // MaxConcurrentRequests is https://github.com/Netflix/Hystrix/wiki/Configuration#executionisolationsemaphoremaxconcurrentrequests MaxConcurrentRequests int64 // Normally if the parent context is canceled before a timeout is reached, we don't consider the circuit // unhealthy. Set this to true to consider those circuits unhealthy. IgnoreInterrupts bool `json:",omitempty"` // IsErrInterrupt should return true if the error from the original context should be considered an interrupt error. // The error passed in will be a non-nil error returned by calling `Err()` on the context passed into Run. // The default behavior is to consider all errors from the original context interrupt caused errors. // Default behaviour: // IsErrInterrupt: function(e err) bool { return true } IsErrInterrupt func(originalContextError error) bool `json:"-"` }
ExecutionConfig is https://github.com/Netflix/Hystrix/wiki/Configuration#execution
type FallbackConfig ¶
type FallbackConfig struct { // Enabled is opposite of https://github.com/Netflix/Hystrix/wiki/Configuration#circuitbreakerenabled // Note: Java Manager calls this "Enabled". I call it "Disabled" so the zero struct can fill defaults Disabled bool `json:",omitempty"` // MaxConcurrentRequests is https://github.com/Netflix/Hystrix/wiki/Configuration#fallback.isolation.semaphore.maxConcurrentRequests MaxConcurrentRequests int64 }
FallbackConfig is https://github.com/Netflix/Hystrix/wiki/Configuration#fallback
type FallbackMetrics ¶
type FallbackMetrics interface { // Success each time fallback is called and succeeds. Success(ctx context.Context, now time.Time, duration time.Duration) // ErrFailure each time fallback callback fails. ErrFailure(ctx context.Context, now time.Time, duration time.Duration) // ErrConcurrencyLimitReject each time fallback fails due to concurrency limit ErrConcurrencyLimitReject(ctx context.Context, now time.Time) }
FallbackMetrics is guaranteed to execute one (and only one) of the following functions each time a fallback is executed. Methods with durations are when the fallback is actually executed. Methods without durations are when the fallback was never called, probably because of some circuit condition.
type FallbackMetricsCollection ¶
type FallbackMetricsCollection []FallbackMetrics
FallbackMetricsCollection sends fallback metrics to all collectors
func (FallbackMetricsCollection) ErrConcurrencyLimitReject ¶
func (r FallbackMetricsCollection) ErrConcurrencyLimitReject(ctx context.Context, now time.Time)
ErrConcurrencyLimitReject sends ErrConcurrencyLimitReject to all collectors
func (FallbackMetricsCollection) ErrFailure ¶
func (r FallbackMetricsCollection) ErrFailure(ctx context.Context, now time.Time, duration time.Duration)
ErrFailure sends ErrFailure to all collectors
func (FallbackMetricsCollection) Success ¶
func (r FallbackMetricsCollection) Success(ctx context.Context, now time.Time, duration time.Duration)
Success sends Success to all collectors
func (FallbackMetricsCollection) Var ¶
func (r FallbackMetricsCollection) Var() expvar.Var
Var exposes run collectors as expvar
type GeneralConfig ¶
type GeneralConfig struct { // if disabled, Execute functions pass to just calling runFunc and do no tracking or fallbacks // Note: Java Manager calls this "Enabled". I call it "Disabled" so the zero struct can fill defaults Disabled bool `json:",omitempty"` // ForceOpen is https://github.com/Netflix/Hystrix/wiki/Configuration#circuitbreakerforceopen ForceOpen bool `json:",omitempty"` // ForcedClosed is https://github.com/Netflix/Hystrix/wiki/Configuration#circuitbreakerforceclosed ForcedClosed bool `json:",omitempty"` // GoLostErrors can receive errors that would otherwise be lost by `Go` executions. For example, if Go returns // early but some long time later an error or panic eventually happens. GoLostErrors func(err error, panics interface{}) `json:"-"` // ClosedToOpenFactory creates logic that determines if the circuit should go from Closed to Open state. // By default, it never opens ClosedToOpenFactory func() ClosedToOpen `json:"-"` // OpenToClosedFactory creates logic that determines if the circuit should go from Open to Closed state. // By default, it never closes OpenToClosedFactory func() OpenToClosed `json:"-"` // CustomConfig is anything you want. CustomConfig map[interface{}]interface{} `json:"-"` // TimeKeeper returns the current way to keep time. You only want to modify this for testing. TimeKeeper TimeKeeper `json:"-"` }
GeneralConfig controls the general logic of the circuit. Things specific to metrics, execution, or fallback are in their own configs
type Manager ¶
type Manager struct { // DefaultCircuitProperties is a list of Config constructors called, in reverse order, // to append or modify configuration for your circuit. DefaultCircuitProperties []CommandPropertiesConstructor // contains filtered or unexported fields }
Manager manages circuits with unique names
func (*Manager) AllCircuits ¶
AllCircuits returns every hystrix circuit tracked
func (*Manager) CreateCircuit ¶
CreateCircuit creates a new circuit, or returns error if a circuit with that name already exists
func (*Manager) GetCircuit ¶
GetCircuit returns the circuit with a given name, or nil if the circuit does not exist. You should not call this in live code. Instead, store the circuit somewhere and use the circuit directly.
func (*Manager) MustCreateCircuit ¶
MustCreateCircuit calls CreateCircuit, but panics if the circuit name already exists
Example (Helloworld) ¶
This example shows how to create a hello-world circuit from the circuit manager
// Manages all our circuits h := circuit.Manager{} // Create a circuit with a unique name c := h.MustCreateCircuit("hello-world") // Call the circuit errResult := c.Execute(context.Background(), func(ctx context.Context) error { return nil }, nil) fmt.Println("Result of execution:", errResult)
Output: Result of execution: <nil>
type Metrics ¶
type Metrics interface { // Closed is called when the circuit transitions from Open to Closed. Closed(ctx context.Context, now time.Time) // Opened is called when the circuit transitions from Closed to Opened. Opened(ctx context.Context, now time.Time) }
Metrics reports internal circuit metric events
type MetricsCollection ¶
type MetricsCollection []Metrics
MetricsCollection allows reporting multiple circuit metrics at once
type MetricsCollectors ¶
type MetricsCollectors struct { Run []RunMetrics `json:"-"` Fallback []FallbackMetrics `json:"-"` Circuit []Metrics `json:"-"` }
MetricsCollectors can receive metrics during a circuit. They should be fast, as they will block circuit operation during function calls.
type OpenToClosed ¶
type OpenToClosed interface { RunMetrics Metrics // ShouldClose is called after a request is allowed to go through, and the circuit is open. If the circuit should // now close, return true. If the circuit should remain open, return false. ShouldClose(ctx context.Context, now time.Time) bool // Allow a single request while remaining in the closed state Allow(ctx context.Context, now time.Time) bool }
OpenToClosed controls logic that tries to close an open circuit
type RunMetrics ¶
type RunMetrics interface { // Success each time `Execute` does not return an error Success(ctx context.Context, now time.Time, duration time.Duration) // ErrFailure each time a runFunc (the circuit part) ran, but failed ErrFailure(ctx context.Context, now time.Time, duration time.Duration) // ErrTimeout increments the number of timeouts that occurred in the circuit breaker. ErrTimeout(ctx context.Context, now time.Time, duration time.Duration) // ErrBadRequest is counts of http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/exception/HystrixBadRequestException.html // See https://github.com/Netflix/Hystrix/wiki/How-To-Use#error-propagation ErrBadRequest(ctx context.Context, now time.Time, duration time.Duration) // ErrInterrupt means the request ended, not because the runFunc failed, but probably because the original // context canceled. Your circuit returned an error, but it's probably because someone else killed the context, // and not that your circuit is broken. Java Manager doesn't have an equivalent for this, but it would be like if // an interrupt was called on the thread. // // A note on stat tracking: you may or may not consider this duration valid. Yes, that's how long it executed, // but the circuit never finished correctly since it was asked to end early, so the value is smaller than the // circuit would have otherwise taken. ErrInterrupt(ctx context.Context, now time.Time, duration time.Duration) // ErrConcurrencyLimitReject each time a circuit is rejected due to concurrency limits ErrConcurrencyLimitReject(ctx context.Context, now time.Time) // ErrShortCircuit each time runFunc is not called because the circuit was open. ErrShortCircuit(ctx context.Context, now time.Time) }
RunMetrics is guaranteed to execute one (and only one) of the following functions each time the circuit attempts to call a run function. Methods with durations are when run was actually executed. Methods without durations never called run, probably because of the circuit.
type RunMetricsCollection ¶
type RunMetricsCollection []RunMetrics
RunMetricsCollection send metrics to multiple RunMetrics
func (RunMetricsCollection) ErrBadRequest ¶
func (r RunMetricsCollection) ErrBadRequest(ctx context.Context, now time.Time, duration time.Duration)
ErrBadRequest sends ErrBadRequest to all collectors
func (RunMetricsCollection) ErrConcurrencyLimitReject ¶
func (r RunMetricsCollection) ErrConcurrencyLimitReject(ctx context.Context, now time.Time)
ErrConcurrencyLimitReject sends ErrConcurrencyLimitReject to all collectors
func (RunMetricsCollection) ErrFailure ¶
func (r RunMetricsCollection) ErrFailure(ctx context.Context, now time.Time, duration time.Duration)
ErrFailure sends ErrFailure to all collectors
func (RunMetricsCollection) ErrInterrupt ¶
func (r RunMetricsCollection) ErrInterrupt(ctx context.Context, now time.Time, duration time.Duration)
ErrInterrupt sends ErrInterrupt to all collectors
func (RunMetricsCollection) ErrShortCircuit ¶
func (r RunMetricsCollection) ErrShortCircuit(ctx context.Context, now time.Time)
ErrShortCircuit sends ErrShortCircuit to all collectors
func (RunMetricsCollection) ErrTimeout ¶
func (r RunMetricsCollection) ErrTimeout(ctx context.Context, now time.Time, duration time.Duration)
ErrTimeout sends ErrTimeout to all collectors
func (RunMetricsCollection) Var ¶
func (r RunMetricsCollection) Var() expvar.Var
Var exposes run collectors as expvar
type SimpleBadRequest ¶
type SimpleBadRequest struct {
Err error
}
SimpleBadRequest is a simple wrapper for an error to mark it as a bad request
func (SimpleBadRequest) BadRequest ¶
func (s SimpleBadRequest) BadRequest() bool
BadRequest always returns true
func (SimpleBadRequest) Cause ¶
func (s SimpleBadRequest) Cause() error
Cause returns the wrapped error
func (SimpleBadRequest) Error ¶
func (s SimpleBadRequest) Error() string
Cause returns the wrapped error
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package closers contains subpackages that control circuit open and close logic.
|
Package closers contains subpackages that control circuit open and close logic. |
hystrix
Package hystrix is a Go implementation of Netflix's Hystrix logic for circuit breakers.
|
Package hystrix is a Go implementation of Netflix's Hystrix logic for circuit breakers. |
simplelogic
Package simplelogic is a holding place for close and open circuit logic that is otherwise simple in use or complexity.
|
Package simplelogic is a holding place for close and open circuit logic that is otherwise simple in use or complexity. |
Run this simple Go program to see what circuits look like.
|
Run this simple Go program to see what circuits look like. |
Package faststats contains helpers to calculate circuit statistics quickly (usually atomically).
|
Package faststats contains helpers to calculate circuit statistics quickly (usually atomically). |
internal
|
|
Package metriceventstream allows exposing your circuit's health as a metric stream that you can visualize with the hystrix dashboard.
|
Package metriceventstream allows exposing your circuit's health as a metric stream that you can visualize with the hystrix dashboard. |
Package metrics contains implementations of MetricsCollectors to aid circuit health detection.
|
Package metrics contains implementations of MetricsCollectors to aid circuit health detection. |
responsetimeslo
Package responsetimeslo contains a MetricsCollector that tracks a SLO metric for circuits.
|
Package responsetimeslo contains a MetricsCollector that tracks a SLO metric for circuits. |
rolling
Package rolling contains a MetricsCollector that tracks in memory rolling stats about a circuit.
|
Package rolling contains a MetricsCollector that tracks in memory rolling stats about a circuit. |