### Install gobreaker Library Source: https://github.com/sony/gobreaker/blob/master/README.md Use 'go get' to install the v2 version of the gobreaker library. ```bash go get github.com/sony/gobreaker/v2 ``` -------------------------------- ### Custom SharedDataStore Implementation Example Source: https://github.com/sony/gobreaker/blob/master/_autodocs/types.md Example of implementing the `SharedDataStore` interface for a custom backend. This includes methods for lock management and data persistence, intended for use with `DistributedCircuitBreaker`. ```go // Implement SharedDataStore for a custom backend type MyStore struct { // fields... } func (s *MyStore) Lock(name string) error { // Acquire lock in your backend return nil } func (s *MyStore) Unlock(name string) error { // Release lock in your backend return nil } func (s *MyStore) GetData(name string) ([]byte, error) { // Fetch state from your backend return []byte{}, nil } func (s *MyStore) SetData(name string, data []byte) error { // Store state in your backend return nil } // Use with DistributedCircuitBreaker dcb, _ := gobreaker.NewDistributedCircuitBreaker[string]( &MyStore{}, settings, ) ``` -------------------------------- ### Example Usage of Circuit Breaker for HTTP GET Source: https://github.com/sony/gobreaker/blob/master/README.md Demonstrates wrapping an HTTP GET request with a circuit breaker to handle potential failures and manage request flow. ```go 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() return io.ReadAll(resp.Body) }) if err != nil { return nil, err } return body, nil } ``` -------------------------------- ### Custom ReadyToTrip: Open after 10 total failures Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Implement a custom ReadyToTrip function to open the circuit breaker after a total number of failures. This example opens the circuit after 10 total failures. ```go func(counts gobreaker.Counts) bool { return counts.TotalFailures >= 10 } ``` -------------------------------- ### Custom ReadyToTrip: Open if failure rate exceeds 50% Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Implement a custom ReadyToTrip function to open the circuit breaker based on a failure rate. This example requires at least 3 requests before deciding and opens if the failure rate is 50% or higher. ```go func(counts gobreaker.Counts) bool { if counts.Requests < 3 { return false // Need at least 3 requests before deciding } failureRate := float64(counts.TotalFailures) / float64(counts.Requests) return failureRate >= 0.5 } ``` -------------------------------- ### Custom ReadyToTrip: Open after 5 consecutive failures Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Implement a custom ReadyToTrip function to open the circuit breaker after a specific number of consecutive failures. This example opens the circuit after 5 failures. ```go func(counts gobreaker.Counts) bool { return counts.ConsecutiveFailures >= 5 } ``` -------------------------------- ### Create TwoStepCircuitBreaker Instance Source: https://github.com/sony/gobreaker/blob/master/_autodocs/twostep-circuitbreaker.md Initializes a new TwoStepCircuitBreaker with specified settings, including name and timeout. This is the starting point for using the two-step circuit breaker pattern. ```Go package main import ( "github.com/sony/gobreaker/v2" "time" ) func main() { scb := gobreaker.NewTwoStepCircuitBreaker[string](gobreaker.Settings{ Name: "AsyncOperation", Timeout: 10 * time.Second, }) } ``` -------------------------------- ### Custom OnStateChange: Multiple monitoring backends Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Implement a comprehensive OnStateChange function that handles multiple monitoring and notification tasks. This example logs the change, records metrics, and sends alerts for open states. ```go func(name string, from, to gobreaker.State) { log.Printf("State change: %s", name) metrics.RecordStateChange(name, from, to) if to == gobreaker.StateOpen { notifications.Alert("Circuit opened: " + name) } } ``` -------------------------------- ### Calculate Failure Rate from Counts Source: https://github.com/sony/gobreaker/blob/master/_autodocs/types.md An example demonstrating how to calculate the failure rate using the Counts structure. This is useful for monitoring service health and triggering circuit breaker actions. ```go counts := cb.Counts() if counts.TotalRequests > 0 { failureRate := float64(counts.TotalFailures) / float64(counts.Requests) if failureRate > 0.5 { log.Printf("Service health: %.2f%% failure rate", failureRate*100) } } ``` -------------------------------- ### Test Custom ReadyToTrip Condition Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Validate custom logic for determining when the circuit breaker should trip to the 'Open' state. This example tests a failure rate condition. ```go func TestFailureRateReadyToTrip(t *testing.T) { cb := gobreaker.NewCircuitBreaker[int](gobreaker.Settings{ ReadyToTrip: func(c gobreaker.Counts) bool { if c.Requests < 5 { return false } failureRate := float64(c.TotalFailures) / float64(c.Requests) return failureRate >= 0.5 }, }) // 4 requests: 2 failures (50% failure rate but < 5 requests) for i := 0; i < 2; i++ { cb.Execute(func() (int, error) { return 0, nil }) cb.Execute(func() (int, error) { return 0, errors.New("fail") }) } assert.Equal(t, gobreaker.StateClosed, cb.State()) // 5th request fails; now 2/5 = 40% failure rate cb.Execute(func() (int, error) { return 0, errors.New("fail") }) assert.Equal(t, gobreaker.StateClosed, cb.State()) // 6th request fails; now 3/6 = 50% failure rate cb.Execute(func() (int, error) { return 0, errors.New("fail") }) assert.Equal(t, gobreaker.StateOpen, cb.State()) } ``` -------------------------------- ### Database Batch Operations with TwoStepCircuitBreaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/twostep-circuitbreaker.md Example of enqueuing a batch write operation using TwoStepCircuitBreaker. The callback is invoked when the batch write operation completes. ```go // Enqueue a batch write operation done, err := tscb.Allow() if err != nil { log.Printf("Batch write rejected: %v", err) return err } // Queue the operation; callback will be invoked when write completes enqueueBatchWrite(func() { result, err := db.Write(batch) done(err) // Report success or failure }) ``` -------------------------------- ### HTTP Client with Timeout using TwoStepCircuitBreaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/twostep-circuitbreaker.md Example of making an HTTP request with manual timeout handling using TwoStepCircuitBreaker. The callback reports the outcome after the request completes. ```go // Make request with manual timeout handling done, err := tscb.Allow() if err != nil { return nil, err } go func(callback func(error)) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _, err := http.DefaultClient.Do(req.WithContext(ctx)) callback(err) // Report outcome after request completes }(done) ``` -------------------------------- ### Get CircuitBreaker Counts Source: https://github.com/sony/gobreaker/blob/master/_autodocs/circuitbreaker.md Obtain a snapshot of internal counters for requests, successes, failures, and consecutive outcomes. Use this for monitoring and performance analysis. ```go counts := cb.Counts() fmt.Printf("Requests: %d, Failures: %d, Success Rate: %.2f%%\n", counts.Requests, counts.TotalFailures, float64(counts.TotalSuccesses) / float64(counts.Requests) * 100, ) ``` -------------------------------- ### Message Queue Processing with TwoStepCircuitBreaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/twostep-circuitbreaker.md Example of processing messages from a queue using TwoStepCircuitBreaker. The callback is invoked when the asynchronous send operation completes. ```go // Process messages from a queue func processMessage(msg *Message) { done, err := tscb.Allow() if err != nil { log.Printf("Circuit breaker rejected: %v", err) // Re-queue the message or discard based on policy return } // Fire-and-forget: send the message, report outcome later go func(callback func(error)) { result, err := sendToDownstream(msg) // Report the outcome when the async operation completes callback(err) }(done) } ``` -------------------------------- ### Get TwoStepCircuitBreaker Counts Source: https://github.com/sony/gobreaker/blob/master/_autodocs/twostep-circuitbreaker.md Fetches a snapshot of the internal counters for requests, successes, failures, and exclusions. This provides metrics for analyzing the circuit breaker's performance. ```Go counts := tscb.Counts() failureRate := float64(counts.TotalFailures) / float64(counts.Requests) fmt.Printf("Failure rate: %.2f%%\n", failureRate*100) ``` -------------------------------- ### Create Redis Store with Basic Connection Source: https://github.com/sony/gobreaker/blob/master/_autodocs/redis-store.md Initializes a new Redis store using a simple address string for the Redis server. ```go store := redis.NewStore("localhost:6379") ``` -------------------------------- ### CircuitBreaker Name Method Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Get the unique name assigned to the circuit breaker instance. ```go Name() string ``` -------------------------------- ### Configure Timeouts with time.Second Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Use the 'time' package to set duration configurations like Timeout, Interval, and BucketPeriod for the circuit breaker settings. ```go import "time" gobreaker.Settings{ Timeout: 30 * time.Second, Interval: 60 * time.Second, BucketPeriod: 10 * time.Second, } ``` -------------------------------- ### Get TwoStepCircuitBreaker Name Source: https://github.com/sony/gobreaker/blob/master/_autodocs/twostep-circuitbreaker.md Retrieves the configured name of the TwoStepCircuitBreaker instance. This is useful for identification and logging purposes. ```Go tscb := gobreaker.NewTwoStepCircuitBreaker[string](gobreaker.Settings{ Name: "EventProcessor", }) fmt.Println(tscb.Name()) // Output: EventProcessor ``` -------------------------------- ### Configuration Callback: ReadyToTrip Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Callback function to determine if the circuit breaker should transition to the open state based on current counts. ```go ReadyToTrip(Counts) bool // Decide when to open ``` -------------------------------- ### Get CircuitBreaker Name Source: https://github.com/sony/gobreaker/blob/master/_autodocs/circuitbreaker.md Retrieve the configured name of the circuit breaker. This is useful for identifying specific breaker instances in logs or metrics. ```go cb := gobreaker.NewCircuitBreaker[string](gobreaker.Settings{ Name: "DatabaseConnection", }) fmt.Println(cb.Name()) // Output: DatabaseConnection ``` -------------------------------- ### Create Redis Store with Cluster Support Source: https://github.com/sony/gobreaker/blob/master/_autodocs/redis-store.md Initializes a new Redis store using a UniversalClient, enabling support for Redis Cluster configurations. ```go client := redis.NewClusterClient(&redis.ClusterOptions{ Addrs: []string{ "localhost:6379", "localhost:6380", "localhost:6381", }, }) store := redis.NewStoreFromClient(client) ``` -------------------------------- ### Custom ReadyToTrip: Open on any failure (aggressive) Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Implement an aggressive ReadyToTrip function that opens the circuit breaker on the first failure. This is useful for immediate response to any error. ```go func(counts gobreaker.Counts) bool { return counts.TotalFailures > 0 } ``` -------------------------------- ### Get TwoStepCircuitBreaker State Source: https://github.com/sony/gobreaker/blob/master/_autodocs/twostep-circuitbreaker.md Returns the current operational state of the TwoStepCircuitBreaker (Closed, HalfOpen, or Open). This helps in monitoring and controlling the circuit breaker's behavior. ```Go state := tscb.State() if state == gobreaker.StateOpen { log.Println("Processing is paused") } ``` -------------------------------- ### Integrate Redis Store with go-redis client Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Initialize a Redis store for distributed circuit breakers using the 'redis' package and a 'go-redis' client. ```go import "github.com/redis/go-redis/v9" import "github.com/sony/gobreaker/v2/redis" store := redis.NewStoreFromClient(redis.NewClient(...)) ``` -------------------------------- ### Create Redis Store from Address Source: https://github.com/sony/gobreaker/blob/master/_autodocs/redis-store.md Use this to create a new Redis store instance. Ensure the Redis server is accessible at the provided address. The store should be closed when no longer needed. ```go package main import ( "github.com/sony/gobreaker/v2" "github.com/sony/gobreaker/v2/redis" ) func main() { store := redis.NewStore("localhost:6379") defer store.Close() dcb, err := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{Name: "MyService"}, ) if err != nil { log.Fatal(err) } } ``` -------------------------------- ### Create Redis Store with Sentinel Support Source: https://github.com/sony/gobreaker/blob/master/_autodocs/redis-store.md Initializes a new Redis store using a FailoverClient, providing support for Redis Sentinel configurations for high availability. ```go client := redis.NewFailoverClient(&redis.FailoverOptions{ SentinelAddrs: []string{ "localhost:26379", "localhost:26380", "localhost:26381", }, MasterName: "mymaster", }) store := redis.NewStoreFromClient(client) ``` -------------------------------- ### Create Redis Store from Existing Client Source: https://github.com/sony/gobreaker/blob/master/_autodocs/redis-store.md Use this to create a Redis store from an already initialized Redis client. This is useful for sharing a Redis connection pool across multiple stores or other application components. ```go import ( "github.com/redis/go-redis/v9" "github.com/sony/gobreaker/v2/redis" ) func main() { // Create a shared Redis client for the entire application redisClient := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) // Create multiple stores from the same client store := redis.NewStoreFromClient(redisClient) dcb1, _ := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{Name: "Service1"}, ) dcb2, _ := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{Name: "Service2"}, ) } ``` -------------------------------- ### Create Distributed Circuit Breaker with All Features Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Initializes a distributed circuit breaker using a Redis store, configuring various features including state change logging and custom error handling. ```Go store := redis.NewStore("localhost:6379") dcb, err := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{ Name: "DistributedService", Timeout: 60 * time.Second, MaxRequests: 5, Interval: 120 * time.Second, BucketPeriod: 10 * time.Second, ReadyToTrip: func(counts gobreaker.Counts) bool { return counts.ConsecutiveFailures > 3 }, OnStateChange: func(name string, from, to gobreaker.State) { log.Printf("Distributed breaker %s: %s → %s", name, from, to) }, IsSuccessful: func(err error) bool { return err == nil }, IsExcluded: func(err error) bool { return errors.Is(err, context.Canceled) }, }, ) ``` -------------------------------- ### Distributed Service Coordination with DistributedCircuitBreaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Initializes a DistributedCircuitBreaker using a Redis store for cross-instance coordination and logs state changes. ```go store := redis.NewStore("redis.example.com:6379") dcb, _ := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{ Name: "SharedDownstream", OnStateChange: func(name string, from, to gobreaker.State) { log.Printf("All instances: %s → %s", from, to) }, }, ) ``` -------------------------------- ### HTTP Client with Fallback using CircuitBreaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Demonstrates how to use a CircuitBreaker to execute an HTTP request and fall back to a cached response if the circuit is open. ```go cb := gobreaker.NewCircuitBreaker[[]byte](gobreaker.Settings{ Name: "HTTPClient", ReadyToTrip: func(c gobreaker.Counts) bool { return c.ConsecutiveFailures > 3 }, }) resp, err := cb.Execute(func() ([]byte, error) { r, _ := http.Get(url) return io.ReadAll(r.Body), nil }) if err != nil { if err == gobreaker.ErrOpenState { return getFromCache(), nil // Use cached response } return nil, err } return resp, nil ``` -------------------------------- ### Create Redis Shared Data Store Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Initialize a Redis-based data store for distributed circuit breaker state synchronization. ```go redis.NewStore(addr string) SharedDataStore ``` ```go redis.NewStoreFromClient(client redis.UniversalClient) SharedDataStore ``` -------------------------------- ### Initialize Distributed Circuit Breaker with Redis Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Initializes a distributed circuit breaker using Redis as the state store. Ensure Redis is accessible at the provided address. Handles potential initialization errors, including cases where no shared state exists. ```go func InitializeDistributedBreaker(redisAddr string) (*gobreaker.DistributedCircuitBreaker[string], error) { store := redis.NewStore(redisAddr) defer store.Close() dcb, err := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{ Name: "SharedService", Timeout: 30 * time.Second, }, ) if err != nil && err != gobreaker.ErrNoSharedState { return nil, fmt.Errorf("failed to initialize distributed breaker: %w", err) } return dcb, nil } ``` -------------------------------- ### Create Production Circuit Breaker with Rolling Window Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Sets up a circuit breaker for production use with a rolling window strategy, defining trip conditions based on failure rate. ```Go cb := gobreaker.NewCircuitBreaker[string](gobreaker.Settings{ Name: "Production", Timeout: 30 * time.Second, MaxRequests: 5, Interval: 60 * time.Second, BucketPeriod: 10 * time.Second, ReadyToTrip: func(counts gobreaker.Counts) bool { if counts.Requests < 5 { return false // Need sample size } failureRate := float64(counts.TotalFailures) / float64(counts.Requests) return failureRate >= 0.5 }, OnStateChange: func(name string, from, to gobreaker.State) { log.Printf("[%s] %s → %s", name, from, to) }, }) ``` -------------------------------- ### Dynamic Circuit Breakers with Registry Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Implement this pattern for microservices that dynamically discover their dependencies. A registry manages circuit breakers, creating new ones as needed for discovered services. ```go type CircuitBreakerRegistry struct { mu sync.RWMutex breakers map[string]*gobreaker.CircuitBreaker[[]byte] } func (r *CircuitBreakerRegistry) Get(serviceName string) *gobreaker.CircuitBreaker[[]byte] { r.mu.RLock() if cb, exists := r.breakers[serviceName]; exists { r.mu.RUnlock() return cb } r.mu.RUnlock() // Create new circuit breaker r.mu.Lock() defer r.mu.Unlock() cb := gobreaker.NewCircuitBreaker[[]byte](gobreaker.Settings{ Name: serviceName, Timeout: 30 * time.Second, }) r.breakers[serviceName] = cb return cb } ``` -------------------------------- ### ReadyToTrip Decision Logic Source: https://github.com/sony/gobreaker/blob/master/_autodocs/internals.md Implements the logic to determine if the circuit breaker should trip based on aggregate counts over a 60-second window. It checks if the request count is sufficient and if the failure rate exceeds a threshold. ```go ReadyToTrip: func(c Counts) bool { // These counts span 60 seconds (6 buckets) if c.Requests < 100 { return false } failureRate := float64(c.TotalFailures) / float64(c.Requests) return failureRate > 0.5 } ``` -------------------------------- ### Rolling Window Metrics with CircuitBreaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Sets up a CircuitBreaker with rolling window metrics to calculate failure rate over specific intervals, requiring a minimum number of requests before tripping. ```go cb := gobreaker.NewCircuitBreaker[string](gobreaker.Settings{ Interval: 60 * time.Second, BucketPeriod: 10 * time.Second, ReadyToTrip: func(c gobreaker.Counts) bool { if c.Requests < 10 { return false // Need sample size } failureRate := float64(c.TotalFailures) / float64(c.Requests) return failureRate > 0.5 }, }) ``` -------------------------------- ### Create New Circuit Breaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Instantiate a new basic circuit breaker with specified settings. ```go NewCircuitBreaker[T](Settings) *CircuitBreaker[T] ``` -------------------------------- ### Distributed Circuit Breaker with Redis Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Sets up a distributed circuit breaker using a Redis backend for state synchronization across multiple instances. It requires a Redis store implementation and the 'gobreaker' package. The 'settings' variable should be configured appropriately. ```go store := redis.NewStore("localhost:6379") dcb, _ := gobreaker.NewDistributedCircuitBreaker[string](store, settings) data, err := dcb.Execute(func() (string, error) { return callDownstream() }) ``` -------------------------------- ### Basic Circuit Breaker for HTTP Requests Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Initializes a basic circuit breaker for HTTP requests and uses it to execute a function that fetches data from a URL. Ensure the 'gobreaker' and 'time' packages are imported. ```go cb := gobreaker.NewCircuitBreaker[[]byte](gobreaker.Settings{ Name: "API", Timeout: 30 * time.Second, }) data, err := cb.Execute(func() ([]byte, error) { resp, _ := http.Get(url) return io.ReadAll(resp.Body), nil }) ``` -------------------------------- ### Main Methods Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md These are the primary methods for interacting with circuit breakers. ```APIDOC ## Main Methods ### CircuitBreaker Methods #### `Execute(func() (T, error)) (T, error)` Executes a function within the circuit breaker. #### `State() State` Returns the current state of the circuit breaker. #### `Counts() Counts` Returns the current counts for the circuit breaker. #### `Name() string` Returns the name of the circuit breaker. ### TwoStepCircuitBreaker Methods #### `Allow() (func(error), error)` Checks if a request is allowed and returns a function to be called upon completion. #### `State() State` Returns the current state of the two-step circuit breaker. #### `Counts() Counts` Returns the current counts for the two-step circuit breaker. #### `Name() string` Returns the name of the two-step circuit breaker. ### DistributedCircuitBreaker Methods #### `Execute(func() (T, error)) (T, error)` Executes a function within the distributed circuit breaker. #### `State() (State, error)` Returns the current state of the distributed circuit breaker. ``` -------------------------------- ### State Transition Logic: Half-Open State Source: https://github.com/sony/gobreaker/blob/master/_autodocs/internals.md Defines the behavior for transitions from the Half-Open state. On success, it tracks consecutive successes and transitions to Closed if the maximum is reached. On the first failure, it immediately transitions back to Open and restarts the timeout. ```go // On success: if cb.counts.ConsecutiveSuccesses >= cb.maxRequests { cb.setState(StateClosed, now) // Recovery successful } // On failure: cb.setState(StateOpen, now) // Back to open; restart timeout ``` -------------------------------- ### Adaptive Timeout Adjustment Wrapper Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Demonstrates a pattern for adapting circuit breaker timeouts based on observed latency metrics. Note that the GoBreaker library itself does not support dynamic timeout adjustments, so this pattern involves wrapping the breaker. ```go type AdaptiveBreaker struct { cb *gobreaker.CircuitBreaker[string] metrics *LatencyMetrics } func (ab *AdaptiveBreaker) AdjustTimeout() { p95 := ab.metrics.Percentile95() // Set timeout to 3x p95 latency newTimeout := time.Duration(float64(p95) * 3) // Note: gobreaker doesn't support dynamic adjustment // This pattern shows how you might wrap it log.Printf("Recommended timeout: %v", newTimeout) } ``` -------------------------------- ### NewStoreFromClient Source: https://github.com/sony/gobreaker/blob/master/_autodocs/redis-store.md Creates a new Redis store from an existing Redis client. This is useful for integrating with existing Redis connection pools and managing circuit breaker state. ```APIDOC ## NewStoreFromClient ### Description Creates a new Redis store from an existing Redis client. Useful for integrating with an existing Redis connection pool. ### Method `NewStoreFromClient(client redis.UniversalClient) gobreaker.SharedDataStore` ### Parameters #### Path Parameters - **client** (redis.UniversalClient) - Required - An existing Redis client (from `redis.NewClient()`, `redis.NewClusterClient()`, or `redis.NewFailoverClient()`) ### Request Example ```go import ( "github.com/redis/go-redis/v9" "github.com/sony/gobreaker/v2/redis" ) func main() { // Create a shared Redis client for the entire application redisClient := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) // Create multiple stores from the same client store := redis.NewStoreFromClient(redisClient) dcb1, _ := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{Name: "Service1"}, ) dcb2, _ := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{Name: "Service2"}, ) } ``` ### Response #### Success Response (200) `gobreaker.SharedDataStore` - A store implementation using the provided client ``` -------------------------------- ### Create Distributed Circuit Breaker with Redis Source: https://github.com/sony/gobreaker/blob/master/_autodocs/distributed-circuitbreaker.md Initializes a new DistributedCircuitBreaker that shares state via a Redis backend. Ensure Redis is running and accessible. The circuit breaker is configured with a name and a timeout. ```go package main import ( "github.com/sony/gobreaker/v2" "github.com/sony/gobreaker/v2/redis" time "time" ) func main() { // Connect to Redis for shared state store := redis.NewStore("localhost:6379") defer store.Close() dcb, err := gobreaker.NewDistributedCircuitBreaker[[]byte]( store, gobreaker.Settings{ Name: "APIClient", Timeout: 30 * time.Second, }, ) if err != nil { log.Fatal(err) } } ``` -------------------------------- ### Graceful Degradation with Fallback Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Handle circuit open states by returning cached or default data instead of an error. This pattern ensures service availability by degrading functionality gracefully. ```go func GetUserProfile(userID string) (*Profile, error) { profile, err := userCB.Execute(func() (*Profile, error) { return fetchFromUserService(userID) }) if err != nil { if err == gobreaker.ErrOpenState { // Service is down; return stale cached data cached := cache.Get(userID) if cached != nil { log.Printf("Using cached profile for user %s", userID) return cached, nil } // No cache available return nil, fmt.Errorf("user service unavailable") } return nil, err } // Cache the fresh result cache.Set(userID, profile) return profile, nil } ``` -------------------------------- ### Retry with Backoff for Transient Failures Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Implement exponential backoff for transient failures to avoid overwhelming a struggling service. This pattern retries the operation a specified number of times with increasing delays. ```go func ExecuteWithRetry(cb *gobreaker.CircuitBreaker[string], maxRetries int) (string, error) { backoff := 100 * time.Millisecond for attempt := 0; attempt < maxRetries; attempt++ { result, err := cb.Execute(func() (string, error) { return callDownstream() }) if err == nil { return result, nil } if err == gobreaker.ErrOpenState { // Circuit is open; don't retry return "", fmt.Errorf("circuit open after %d attempts", attempt) } if attempt < maxRetries-1 { time.Sleep(backoff) backoff *= 2 // Exponential backoff } } return "", fmt.Errorf("failed after %d retries", maxRetries) } ``` -------------------------------- ### Configure BucketPeriod for Rolling Window Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Set the duration of each bucket in the rolling window strategy for time-series metrics. If less than or equal to 0, a fixed window strategy is used. ```go // Rolling window with 1-second buckets, 10-second window settings := gobreaker.Settings{ Interval: 10 * time.Second, BucketPeriod: 1 * time.Second, } ``` -------------------------------- ### Mock Circuit Breaker for Unit Testing Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Implement a mock circuit breaker for unit testing your application logic. This allows you to isolate your code and control the breaker's behavior during tests. ```go type MockCircuitBreaker struct { ExecuteFn func(func() (interface{}, error)) (interface{}, error) } func (m *MockCircuitBreaker) Execute(fn func() (interface{}, error)) (interface{}, error) { return m.ExecuteFn(fn) } func TestMyFunction(t *testing.T) { mcb := &MockCircuitBreaker{ ExecuteFn: func(fn func() (interface{}, error)) (interface{}, error) { return "mocked result", nil }, } // Use mcb in your code result, _ := mcb.Execute(func() (interface{}, error) { return "test", nil }) assert.Equal(t, "mocked result", result) } ``` -------------------------------- ### Collect Metrics for Monitoring Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Collect metrics on state changes, opens, and closes for monitoring purposes. This requires Prometheus client library integration. ```go type Metrics struct { stateChanges prometheus.Counter opens prometheus.Counter closes prometheus.Counter } gobreaker.Settings{ Name: "Service", OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) { m.stateChanges.WithLabelValues(name, to.String()).Inc() if to == gobreaker.StateOpen { m.opens.WithLabelValues(name).Inc() } if to == gobreaker.StateClosed { m.closes.WithLabelValues(name).Inc() } }, } ``` -------------------------------- ### NewStore Source: https://github.com/sony/gobreaker/blob/master/_autodocs/redis-store.md Creates a new Redis store that connects to a Redis instance at the specified address. This store can be used to manage distributed circuit breaker state. ```APIDOC ## NewStore ### Description Creates a new Redis store that connects to a Redis instance at the specified address. ### Method `NewStore(addr string) gobreaker.SharedDataStore` ### Parameters #### Path Parameters - **addr** (string) - Required - Redis server address in format `host:port` (e.g., `localhost:6379`) ### Request Example ```go package main import ( "github.com/sony/gobreaker/v2" "github.com/sony/gobreaker/v2/redis" ) func main() { store := redis.NewStore("localhost:6379") defer store.Close() dcb, err := gobreaker.NewDistributedCircuitBreaker[string]( store, gobreaker.Settings{Name: "MyService"}, ) if err != nil { log.Fatal(err) } } ``` ### Response #### Success Response (200) `gobreaker.SharedDataStore` - A store implementation that can be passed to `NewDistributedCircuitBreaker` ``` -------------------------------- ### Configuration Callbacks Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Callbacks that can be used to customize circuit breaker behavior. ```APIDOC ## Configuration Callbacks ### `ReadyToTrip(Counts) bool` A function that determines if the circuit breaker should transition to the open state based on current counts. ### `IsSuccessful(error) bool` A function that determines if an error indicates a successful operation (e.g., for error-tolerant scenarios). ### `IsExcluded(error) bool` A function that determines if a specific error should be ignored and not counted against the circuit breaker's thresholds. ### `OnStateChange(name string, from, to State)` A callback function that is executed whenever the circuit breaker's state changes. ``` -------------------------------- ### Handle Context Cancellation with context.Canceled Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Utilize the 'context' package to define exclusion logic for circuit breaker errors, specifically for context cancellation. ```go import "context" gobreaker.Settings{ IsExcluded: func(err error) bool { return errors.Is(err, context.Canceled) }, } ``` -------------------------------- ### Create New Two-Step Circuit Breaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Instantiate a new two-step circuit breaker, suitable for async operations, with specified settings. ```go NewTwoStepCircuitBreaker[T](Settings) *TwoStepCircuitBreaker[T] ``` -------------------------------- ### Configuration Callback: OnStateChange Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Callback function to be executed whenever the circuit breaker's state changes, providing the name, previous state, and new state. ```go OnStateChange(name string, from, to State) // React to state change ``` -------------------------------- ### Basic Circuit Breaker Usage Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Create and use a basic circuit breaker for synchronous operations. Wrap HTTP requests to protect against failures. ```go import "github.com/sony/gobreaker/v2" // Create a circuit breaker for your return type cb := gobreaker.NewCircuitBreaker[[]byte](gobreaker.Settings{ Name: "API", Timeout: 30 * time.Second, }) // Wrap requests data, err := cb.Execute(func() ([]byte, error) { resp, err := http.Get("https://api.example.com/data") if err != nil { return nil, err } defer resp.Body.Close() return io.ReadAll(resp.Body) }) ``` -------------------------------- ### Global Circuit Breaker Initialization Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Use this pattern to create a single circuit breaker instance for a shared downstream dependency across the application. The breaker is initialized in the init function. ```go package main import ( "github.com/sony/gobreaker/v2" "time" ) var downstreamAPI *gobreaker.CircuitBreaker[[]byte] func init() { downstreamAPI = gobreaker.NewCircuitBreaker[[]byte](gobreaker.Settings{ Name: "DownstreamAPI", Timeout: 30 * time.Second, }) } func FetchData(ctx context.Context, id string) ([]byte, error) { data, err := downstreamAPI.Execute(func() ([]byte, error) { return callDownstream(ctx, id) }) if err != nil { return nil, err } return data, nil } ``` -------------------------------- ### Rolling Window Bucket Count Source: https://github.com/sony/gobreaker/blob/master/_autodocs/internals.md Calculates the number of buckets for the rolling window based on Interval and BucketPeriod. ```go With Interval=60s and BucketPeriod=10s: N = 6 buckets ``` -------------------------------- ### Circuit Breaker for Asynchronous Operations Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Demonstrates how to use a TwoStepCircuitBreaker for asynchronous operations, such as those in a message queue. It checks if an operation is allowed and then executes it asynchronously. Requires importing the 'gobreaker' package. ```go tscb := gobreaker.NewTwoStepCircuitBreaker[string](...) done, err := tscb.Allow() if err == nil { go func() { done(asyncOperation()) }() } ``` -------------------------------- ### Per-Dependency Circuit Breakers Source: https://github.com/sony/gobreaker/blob/master/_autodocs/usage-patterns.md Create a separate circuit breaker for each external service when managing multiple dependencies. This allows for independent monitoring and control of each service's circuit. ```go type Services struct { AuthService *gobreaker.CircuitBreaker[*User] DatabaseAPI *gobreaker.CircuitBreaker[[]byte] NotificationSvc *gobreaker.CircuitBreaker[string] } func NewServices() *Services { return &Services{ AuthService: gobreaker.NewCircuitBreaker[*User](gobreaker.Settings{ Name: "AuthService", }), DatabaseAPI: gobreaker.NewCircuitBreaker[[]byte](gobreaker.Settings{ Name: "DatabaseAPI", }), NotificationSvc: gobreaker.NewCircuitBreaker[string](gobreaker.Settings{ Name: "NotificationService", }), } } ``` -------------------------------- ### Configuration Callback: IsSuccessful Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md Callback function to define what constitutes a successful operation, typically by inspecting the returned error. ```go IsSuccessful(error) bool // Determine success ``` -------------------------------- ### Exclude Context Cancellations and Timeouts Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Implement IsExcluded to ignore context cancellation and deadline exceeded errors for metrics. ```Go func(err error) bool { return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) } ``` -------------------------------- ### Configure HTTP Circuit Breaker with Status Code Handling Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Customizes the IsSuccessful function to treat HTTP 5xx errors as failures and 4xx errors as successes, while network errors are failures. ```Go cb := gobreaker.NewCircuitBreaker[[]byte](gobreaker.Settings{ Name: "HTTPClient", Timeout: 30 * time.Second, IsSuccessful: func(err error) bool { if err == nil { return true } // Treat 5xx as failure, 4xx as success var urlErr *url.Error if errors.As(err, &urlErr) { // Network error is a failure return false } return false }, }) ``` -------------------------------- ### Constructors Source: https://github.com/sony/gobreaker/blob/master/_autodocs/INDEX.md These functions are used to create new instances of circuit breakers. ```APIDOC ## Constructors ### `NewCircuitBreaker[T](Settings) *CircuitBreaker[T]` Creates a new basic circuit breaker. ### `NewTwoStepCircuitBreaker[T](Settings) *TwoStepCircuitBreaker[T]` Creates a new two-step circuit breaker. ### `NewDistributedCircuitBreaker[T](SharedDataStore, Settings) (*DistributedCircuitBreaker[T], error)` Creates a new distributed circuit breaker. ### `redis.NewStore(addr string) SharedDataStore` Creates a new Redis-based shared data store. ### `redis.NewStoreFromClient(client redis.UniversalClient) SharedDataStore` Creates a new Redis-based shared data store from an existing client. ``` -------------------------------- ### Create Conservative Circuit Breaker Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Initializes a circuit breaker with default settings, suitable for most basic use cases. Timeout is set to 60 seconds. ```Go cb := gobreaker.NewCircuitBreaker[string](gobreaker.Settings{ Name: "MyService", Timeout: 60 * time.Second, // All other fields use defaults // MaxRequests: 1 // Interval: 0 // ReadyToTrip: > 5 consecutive failures }) ``` -------------------------------- ### Configure MaxRequests for Half-Open State Source: https://github.com/sony/gobreaker/blob/master/_autodocs/configuration.md Set the maximum number of test requests allowed in the Half-Open state. A value of 0 defaults to 1. ```go // Allow up to 5 test requests when half-open settings := gobreaker.Settings{ MaxRequests: 5, } // Only 1 test request at a time (default) settings = gobreaker.Settings{ MaxRequests: 0, // Automatically set to 1 } ``` -------------------------------- ### Synchronous CircuitBreaker Execution Flow Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Illustrates the internal state checks and execution flow of a synchronous CircuitBreaker. ```text ┌─────────────────────┐ │ cb.Execute(req) │ └──────────┬──────────┘ │ ▼ ┌─────────────────┐ │ Check state │ │ - Open? │ - Half-Open │ │ too many? └──────┬──────────┘ │ ├─ Error? ──> return error │ ▼ ┌─────────────────┐ │ Execute req() │ └──────┬──────────┘ │ ├─ Panic? ──> record failure, re-panic │ ▼ ┌─────────────────┐ │ Check result │ │ - IsExcluded? │ - IsSuccessful? │ └──────┬──────────┘ │ ├─ Excluded? ──> increment exclusions │ ├─ Success? ──> increment successes, │ check state transition │ ├─ Failure? ──> increment failures, │ check ReadyToTrip() │ ▼ return (result, err) ``` -------------------------------- ### State Transition Logic: Open State Source: https://github.com/sony/gobreaker/blob/master/_autodocs/internals.md Manages transitions from the Open state. If the timeout expires, it automatically transitions to the Half-Open state to allow for recovery attempts. Requests are rejected with ErrOpenState while in this state. ```go case StateOpen: if cb.expiry.Before(now) { cb.setState(StateHalfOpen, now) // Timeout expired; try recovery } ``` -------------------------------- ### Inspect Circuit Breaker State Programmatically in Go Source: https://github.com/sony/gobreaker/blob/master/_autodocs/internals.md This function demonstrates how to programmatically inspect the current state and counts of a gobreaker circuit breaker. It prints key metrics like state, total requests, successes, failures, and consecutive failures. ```go func inspectBreaker(cb *gobreaker.CircuitBreaker[string]) { state := cb.State() counts := cb.Counts() fmt.Printf("State: %s\n", state) fmt.Printf("Requests: %d\n", counts.Requests) fmt.Printf("Successes: %d\n", counts.TotalSuccesses) fmt.Printf("Failures: %d\n", counts.TotalFailures) fmt.Printf("Consecutive Failures: %d\n", counts.ConsecutiveFailures) } ``` -------------------------------- ### Two-Step Circuit Breaker with Error Reporting Source: https://github.com/sony/gobreaker/blob/master/_autodocs/errors.md Utilize the two-step `Allow()` method for asynchronous operations. This pattern involves checking if an operation is allowed, scheduling it, and then reporting its outcome using the `done` function. ```go done, err := tscb.Allow() if err != nil { if err == gobreaker.ErrOpenState { log.Println("Async operation rejected") } return err } // Schedule async operation go func() { result, err := performAsyncOperation() done(err) // Report outcome }() return nil ``` -------------------------------- ### Handling Redis Connection Errors Source: https://github.com/sony/gobreaker/blob/master/_autodocs/errors.md Check for specific Redis errors like `redis.Nil` for non-existent keys or general network/authentication issues. This pattern is useful when interacting with Redis for shared state management. ```go data, err := store.GetData("gobreaker:state:MyBreaker") if err != nil { if err == redis.Nil { // Key not found; this is expected for new breakers log.Println("Shared state not yet created") } else { // Network or Redis error log.Printf("Failed to read from Redis: %v", err) return err } } ``` -------------------------------- ### Circuit Breaker Generation Counter Source: https://github.com/sony/gobreaker/blob/master/_autodocs/internals.md Illustrates the use of a 64-bit generation counter within the CircuitBreaker struct to detect and discard stale requests that were accepted in a previous state generation. ```go type CircuitBreaker[T any] struct { generation uint64 // Increments on state transitions // ... } ``` -------------------------------- ### Test Circuit Breaker State Transitions Source: https://github.com/sony/gobreaker/blob/master/_autodocs/internals.md This test function demonstrates how to force state transitions in a circuit breaker for testing purposes. It triggers an open state and then waits for it to transition to half-open. ```go func TestStateTransition(t *testing.T) { cb := gobreaker.NewCircuitBreaker[int](gobreaker.Settings{ Name: "test", Timeout: 1 * time.Millisecond, ReadyToTrip: func(c gobreaker.Counts) bool { return c.ConsecutiveFailures >= 1 }, }) // Trigger open cb.Execute(func() (int, error) { return 0, errors.New("fail") }) assert.Equal(t, gobreaker.StateOpen, cb.State()) // Wait for half-open time.Sleep(2 * time.Millisecond) assert.Equal(t, gobreaker.StateHalfOpen, cb.State()) } ``` -------------------------------- ### Two-Step Circuit Breaker for Async Operations Source: https://github.com/sony/gobreaker/blob/master/_autodocs/README.md Implement a two-step circuit breaker for asynchronous operations. This pattern separates the decision to allow a request from the reporting of its outcome. ```go tscb := gobreaker.NewTwoStepCircuitBreaker[string](gobreaker.Settings{ Name: "AsyncOp", }) // Check if request is allowed done, err := tscb.Allow() if err != nil { return err // Circuit breaker rejected } // Execute asynchronously, report result later go func() { result, err := asyncOperation() done(err) // Report outcome }() ```