Skip to content

The Circuit Breaker pattern is used to protect a system from failures in its external dependencies.

License

Notifications You must be signed in to change notification settings

farzai/breaker-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Circuit Breaker in Golang

Go Reference Go Report Card Github Actions codecov GitHub release Go Version License

This repository contains a simple implementation of the Circuit Breaker in Golang.

Overview

The Circuit Breaker pattern is used to protect a system from failures in its external dependencies. It helps to improve the system's resiliency by preventing cascading failures and allowing the system to recover gracefully when a dependency fails.

The Circuit Breaker implementation in this repository has three main states:

  • Closed: The external dependency is considered healthy, and all requests are executed as expected.
  • Open: The external dependency is considered unhealthy, and no requests are executed to prevent further failures.
  • Half-Open: The external dependency is being tested for healthiness, and a limited number of requests are executed to determine if the dependency has recovered.

Installation

go get -u github.com/farzai/breaker-go

Usage

To use the Circuit Breaker, first import the breaker package:

import "github.com/farzai/breaker-go"

func main() {
    // Create a new Circuit Breaker instance with the desired failure threshold and reset timeout:
    cb := breaker.NewCircuitBreaker(3, 5*time.Second)

    // Wrap any function that communicates with an external dependency using the Execute method of the Circuit Breaker:
    result, err := cb.Execute(func() (interface{}, error) {
        // Code to interact with the external dependency
    })

    // Handle the result of the function call
}

State Persistence

The Circuit Breaker supports persisting its state to survive application restarts. You can choose between in-memory storage (default) or file-based storage.

In-Memory Storage (Default)

By default, the circuit breaker uses in-memory storage, which is fast but doesn't persist across restarts:

cb := breaker.NewCircuitBreaker(3, 5*time.Second)

File-Based Storage

For persistent state storage, use the file-based repository:

// Option 1: Use a temporary file (recommended for most cases)
repo, err := breaker.NewTempFileSnapshotRepository()
if err != nil {
    log.Fatal(err)
}

cb := breaker.NewCircuitBreaker(
    3,
    5*time.Second,
    breaker.WithSnapshotRepository(repo),
)

// Option 2: Specify a custom file path
repo, err := breaker.NewFileSnapshotRepository("/var/app/circuit_breaker.json")
if err != nil {
    log.Fatal(err)
}

cb := breaker.NewCircuitBreaker(
    3,
    5*time.Second,
    breaker.WithSnapshotRepository(repo),
)

// Option 3: Use advanced options
repo, err := breaker.NewFileSnapshotRepositoryWithOptions(breaker.FileSnapshotRepositoryOptions{
    DirPath:  "/var/app/state",
    FileName: "circuit_breaker_snapshot.json",
})
if err != nil {
    log.Fatal(err)
}

cb := breaker.NewCircuitBreaker(
    3,
    5*time.Second,
    breaker.WithSnapshotRepository(repo),
)

The file-based repository provides:

  • Atomic writes: State changes are written atomically to prevent corruption
  • Thread-safe operations: Safe for concurrent use
  • Automatic directory creation: Parent directories are created automatically
  • JSON serialization: Human-readable snapshot format

Logging & Observability

The circuit breaker includes comprehensive structured logging support for production observability.

Basic Logging

import "github.com/farzai/breaker-go/logging"

// Create a logger with INFO level
logger := logging.NewDefaultLogger(logging.LevelInfo)

cb, err := breaker.New(
    breaker.WithFailureThreshold(3),
    breaker.WithResetTimeout(5*time.Second),
    breaker.WithLogger(logger),
)

Log Levels

  • Debug: Detailed execution traces, persistence operations
  • Info: State transitions, important events
  • Warn: Circuit breaker blocking requests
  • Error: Operation failures, persistence errors

Quick Setup

// Convenience option for quick setup
cb, err := breaker.New(
    breaker.WithLogLevel(logging.LevelInfo),
)

Integration with Popular Loggers

Go's standard slog (Go 1.21+):

import "log/slog"

handler := slog.NewJSONHandler(os.Stdout, nil)
slogger := slog.New(handler)
logger := logging.NewSlogAdapter(slogger)

cb, err := breaker.New(
    breaker.WithLogger(logger),
)

Advanced Configuration

Builder pattern:

logger := logging.NewBuilder().
    WithLevel(logging.LevelInfo).
    WithFields(
        logging.String("service", "api"),
        logging.String("version", "1.0.0"),
    ).
    Build()

cb, err := breaker.New(
    breaker.WithLogger(logger),
)

Separate persistence logger:

mainLogger := logging.NewDefaultLogger(logging.LevelInfo)
persistLogger := logging.NewDefaultLogger(logging.LevelDebug)

cb, err := breaker.New(
    breaker.WithLogger(mainLogger),
    breaker.WithPersistenceLogger(persistLogger),
)

What Gets Logged

  • ✅ State transitions (Closed → Open → HalfOpen)
  • ✅ Execution attempts and results
  • ✅ Persistence operations (save/load with timing)
  • ✅ Manual reset operations
  • ✅ Configuration validation errors
  • ✅ Retry attempts with delays

Examples

See the examples/ directory for complete logging examples:

  • logging_basic.go - Basic logging setup
  • logging_advanced.go - Custom adapters and patterns

Testing

Unit tests for the Circuit Breaker can be found in the breaker_test.go file. To run the tests, use the following command:

go test

License

This project is licensed under the MIT License - see the MIT license for details.

About

The Circuit Breaker pattern is used to protect a system from failures in its external dependencies.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages