Top Related Projects
⏱ The exponential backoff algorithm in Go
Resiliency patterns for golang
Netflix's Hystrix latency and fault tolerance library, for Go
Circuit Breakers in Go
Quick Overview
Sony/gobreaker is a Go implementation of the Circuit Breaker pattern. It helps prevent cascading failures in distributed systems by temporarily disabling operations that are likely to fail, allowing the system to recover and reducing the impact of failures.
Pros
- Lightweight and easy to integrate into Go applications
- Configurable with customizable settings for failure thresholds and recovery time
- Thread-safe implementation suitable for concurrent use
- Well-documented with clear examples and explanations
Cons
- Limited to Go applications, not suitable for other programming languages
- Requires manual integration into each service or function that needs protection
- May introduce additional complexity to the codebase
- Potential for false positives if not configured correctly
Code Examples
- Creating a Circuit Breaker:
var cb *gobreaker.CircuitBreaker
st := gobreaker.Settings{
Name: "HTTP GET",
Timeout: 10 * time.Second,
}
cb = gobreaker.NewCircuitBreaker(st)
- Using the Circuit Breaker:
body, err := cb.Execute(func() (interface{}, error) {
resp, err := http.Get("http://example.com/")
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
})
- Custom error handling:
st := gobreaker.Settings{
Name: "CustomErrorHandler",
ReadyToTrip: func(counts gobreaker.Counts) bool {
failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
return counts.Requests >= 3 && failureRatio >= 0.6
},
}
cb := gobreaker.NewCircuitBreaker(st)
Getting Started
To use sony/gobreaker in your Go project:
-
Install the package:
go get github.com/sony/gobreaker
-
Import the package in your Go code:
import "github.com/sony/gobreaker"
-
Create and use a Circuit Breaker as shown in the code examples above.
Competitor Comparisons
⏱ The exponential backoff algorithm in Go
Pros of backoff
- More flexible retry strategies, including exponential backoff with jitter
- Supports both time-based and attempt-based retry limits
- Can be used for various scenarios beyond circuit breaking
Cons of backoff
- Lacks built-in circuit breaking functionality
- Doesn't provide state management for tracking failures across requests
- May require more manual configuration for complex retry scenarios
Code Comparison
backoff:
b := backoff.NewExponentialBackOff()
err := backoff.Retry(operation, b)
gobreaker:
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{})
result, err := cb.Execute(func() (interface{}, error) {
// Your operation here
})
Summary
backoff is a more general-purpose retry library with flexible backoff strategies, while gobreaker focuses specifically on implementing the circuit breaker pattern. backoff offers more control over retry behavior but requires additional implementation for circuit breaking. gobreaker provides a simpler interface for circuit breaking but has less flexibility in retry strategies.
Choose backoff if you need fine-grained control over retry behavior across various scenarios. Opt for gobreaker if you specifically need circuit breaking functionality with minimal configuration.
Both libraries are well-maintained and have their strengths, so the choice depends on your specific use case and requirements.
Resiliency patterns for golang
Pros of go-resiliency
- Offers multiple resilience patterns (Circuit Breaker, Retrier, Semaphore) in a single package
- Provides more flexibility and customization options for each pattern
- Includes a Semaphore implementation for concurrency control
Cons of go-resiliency
- Less focused on circuit breaking specifically, which may lead to a more complex API
- Not as actively maintained as gobreaker (fewer recent updates and contributions)
- May have a steeper learning curve due to the variety of patterns offered
Code Comparison
go-resiliency (Circuit Breaker):
cb := circuitbreaker.NewThresholdBreaker(10)
result, err := cb.Execute(func() (interface{}, error) {
// Your code here
return nil, nil
})
gobreaker:
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{})
result, err := cb.Execute(func() (interface{}, error) {
// Your code here
return nil, nil
})
Both libraries offer similar usage patterns for circuit breaking, with gobreaker providing a more streamlined API focused solely on circuit breaking functionality. go-resiliency offers additional resilience patterns but may require more setup and configuration for specific use cases.
Netflix's Hystrix latency and fault tolerance library, for Go
Pros of hystrix-go
- More comprehensive circuit breaker implementation with additional features like request collapsing and request caching
- Provides a dashboard for real-time monitoring of circuit breaker status
- Offers more granular control over circuit breaker behavior and configuration
Cons of hystrix-go
- More complex to set up and use compared to gobreaker's simpler API
- Less actively maintained, with fewer recent updates and contributions
- Heavier dependency footprint, which may increase project complexity
Code Comparison
hystrix-go:
hystrix.ConfigureCommand("my_command", hystrix.CommandConfig{
Timeout: 1000,
MaxConcurrentRequests: 100,
ErrorPercentThreshold: 25,
})
err := hystrix.Do("my_command", func() error {
// Make API call or perform operation
return nil
}, nil)
gobreaker:
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: "my-breaker",
MaxRequests: 100,
Interval: 5 * time.Second,
Timeout: 1 * time.Second,
})
result, err := cb.Execute(func() (interface{}, error) {
// Make API call or perform operation
return nil, nil
})
Both libraries provide circuit breaker functionality, but hystrix-go offers a more feature-rich implementation at the cost of increased complexity. gobreaker provides a simpler, more straightforward approach that may be sufficient for many use cases.
Circuit Breakers in Go
Pros of circuitbreaker
- Written in Ruby, making it a natural choice for Ruby projects
- Simpler API with fewer configuration options, potentially easier to use
- Supports custom error handling and logging
Cons of circuitbreaker
- Less actively maintained (last update was several years ago)
- Fewer features and customization options compared to gobreaker
- Limited documentation and examples available
Code Comparison
circuitbreaker:
circuit = CircuitBreaker.new do |cb|
cb.timeout = 5
cb.failure_threshold = 5
cb.failure_timeout = 10
end
circuit.run do
# Your code here
end
gobreaker:
st := gobreaker.Settings{
Name: "HTTP GET",
MaxRequests: 3,
Interval: 10 * time.Second,
Timeout: 30 * time.Second,
}
cb := gobreaker.NewCircuitBreaker(st)
result, err := cb.Execute(func() (interface{}, error) {
// Your code here
})
Both libraries provide similar functionality for implementing the circuit breaker pattern. gobreaker offers more configuration options and is actively maintained, making it a more robust choice for Go projects. circuitbreaker is simpler and may be preferable for Ruby developers who need basic circuit breaker functionality.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
gobreaker
gobreaker implements the Circuit Breaker pattern in Go.
Installation
go get github.com/sony/gobreaker/v2
Usage
The struct CircuitBreaker
is a state machine to prevent sending requests that are likely to fail.
The function NewCircuitBreaker
creates a new CircuitBreaker
.
The type parameter T
specifies the return type of requests.
func NewCircuitBreaker[T any](st Settings) *CircuitBreaker[T]
You can configure CircuitBreaker
by the struct Settings
:
type Settings struct {
Name string
MaxRequests uint32
Interval time.Duration
Timeout time.Duration
ReadyToTrip func(counts Counts) bool
OnStateChange func(name string, from State, to State)
IsSuccessful func(err error) bool
}
-
Name
is the name of theCircuitBreaker
. -
MaxRequests
is the maximum number of requests allowed to pass through when theCircuitBreaker
is half-open. IfMaxRequests
is 0,CircuitBreaker
allows only 1 request. -
Interval
is the cyclic period of the closed state forCircuitBreaker
to clear the internalCounts
, described later in this section. IfInterval
is 0,CircuitBreaker
doesn't clear the internalCounts
during the closed state. -
Timeout
is the period of the open state, after which the state ofCircuitBreaker
becomes half-open. IfTimeout
is 0, the timeout value ofCircuitBreaker
is set to 60 seconds. -
ReadyToTrip
is called with a copy ofCounts
whenever a request fails in the closed state. IfReadyToTrip
returns true,CircuitBreaker
will be placed into the open state. IfReadyToTrip
isnil
, defaultReadyToTrip
is used. DefaultReadyToTrip
returns true when the number of consecutive failures is more than 5. -
OnStateChange
is called whenever the state ofCircuitBreaker
changes. -
IsSuccessful
is called with the error returned from a request. IfIsSuccessful
returns true, the error is counted as a success. Otherwise the error is counted as a failure. IfIsSuccessful
is nil, defaultIsSuccessful
is used, which returns false for all non-nil errors.
The struct Counts
holds the numbers of requests and their successes/failures:
type Counts struct {
Requests uint32
TotalSuccesses uint32
TotalFailures uint32
ConsecutiveSuccesses uint32
ConsecutiveFailures uint32
}
CircuitBreaker
clears the internal Counts
either
on the change of the state or at the closed-state intervals.
Counts
ignores the results of the requests sent before clearing.
CircuitBreaker
can wrap any function to send a request:
func (cb *CircuitBreaker[T]) Execute(req func() (T, error)) (T, error)
The method Execute
runs the given request if CircuitBreaker
accepts it.
Execute
returns an error instantly if CircuitBreaker
rejects the request.
Otherwise, Execute
returns the result of the request.
If a panic occurs in the request, CircuitBreaker
handles it as an error
and causes the same panic again.
Example
var cb *gobreaker.CircuitBreaker[[]byte]
func Get(url string) ([]byte, error) {
body, err := cb.Execute(func() ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
})
if err != nil {
return nil, err
}
return body, nil
}
See example for details.
License
The MIT License (MIT)
See LICENSE for details.
Top Related Projects
⏱ The exponential backoff algorithm in Go
Resiliency patterns for golang
Netflix's Hystrix latency and fault tolerance library, for Go
Circuit Breakers in Go
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot