Convert Figma logo to code with AI

sony logogobreaker

Circuit Breaker implemented in Go

2,887
179
2,887
21

Top Related Projects

3,397

⏱ 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

  1. Creating a Circuit Breaker:
var cb *gobreaker.CircuitBreaker

st := gobreaker.Settings{
    Name:    "HTTP GET",
    Timeout: 10 * time.Second,
}

cb = gobreaker.NewCircuitBreaker(st)
  1. 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)
})
  1. 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:

  1. Install the package:

    go get github.com/sony/gobreaker
    
  2. Import the package in your Go code:

    import "github.com/sony/gobreaker"
    
  3. Create and use a Circuit Breaker as shown in the code examples above.

Competitor Comparisons

3,397

⏱ 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 Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

gobreaker

GoDoc

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 the CircuitBreaker.

  • MaxRequests is the maximum number of requests allowed to pass through when the CircuitBreaker is half-open. If MaxRequests is 0, CircuitBreaker allows only 1 request.

  • Interval is the cyclic period of the closed state for CircuitBreaker to clear the internal Counts, described later in this section. If Interval is 0, CircuitBreaker doesn't clear the internal Counts during the closed state.

  • Timeout is the period of the open state, after which the state of CircuitBreaker becomes half-open. If Timeout is 0, the timeout value of CircuitBreaker is set to 60 seconds.

  • ReadyToTrip is called with a copy of Counts whenever a request fails in the closed state. If ReadyToTrip returns true, CircuitBreaker will be placed into the open state. If ReadyToTrip is nil, default ReadyToTrip is used. Default ReadyToTrip returns true when the number of consecutive failures is more than 5.

  • OnStateChange is called whenever the state of CircuitBreaker changes.

  • IsSuccessful is called with the error returned from a request. If IsSuccessful returns true, the error is counted as a success. Otherwise the error is counted as a failure. If IsSuccessful is nil, default IsSuccessful 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.