This repository contains a simple implementation of the Circuit Breaker in Golang.
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.
 
go get -u github.com/farzai/breaker-goTo 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
}The Circuit Breaker supports persisting its state to survive application restarts. You can choose between in-memory storage (default) or file-based storage.
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)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
 
The circuit breaker includes comprehensive structured logging support for production observability.
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),
)- Debug: Detailed execution traces, persistence operations
 - Info: State transitions, important events
 - Warn: Circuit breaker blocking requests
 - Error: Operation failures, persistence errors
 
// Convenience option for quick setup
cb, err := breaker.New(
    breaker.WithLogLevel(logging.LevelInfo),
)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),
)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),
)- ✅ 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
 
See the examples/ directory for complete logging examples:
logging_basic.go- Basic logging setuplogging_advanced.go- Custom adapters and patterns
Unit tests for the Circuit Breaker can be found in the breaker_test.go file. To run the tests, use the following command:
go testThis project is licensed under the MIT License - see the MIT license for details.