| Crates.io | circuitbreaker-rs |
| lib.rs | circuitbreaker-rs |
| version | 0.1.1 |
| created_at | 2025-05-24 06:34:57.791833+00 |
| updated_at | 2025-05-24 06:57:22.017865+00 |
| description | A production-grade, zero-boilerplate, lock-efficient, observability-ready Circuit Breaker library |
| homepage | |
| repository | https://github.com/copyleftdev/circuitbreaker-rs |
| max_upload_size | |
| id | 1687056 |
| size | 134,836 |
A production-grade, zero-boilerplate, lock-efficient, observability-ready Circuit Breaker library for Rust applications. Fast, reliable, and well-tested.
Implemented by copyleftdev.
circuitbreaker-rs is a high-performance circuit breaker implementation designed for integration into performance-critical Rust systems. It provides both synchronous and asynchronous interfaces, integrates with observability stacks, and supports custom policies, configurable time-windows, and recovery strategies.
The Circuit Breaker pattern is used to improve system resilience by detecting failures and preventing cascading failures throughout the system. It works like an electrical circuit breaker:
This pattern is essential for building resilient distributed systems, microservices, and applications that interact with external dependencies.
Add the dependency to your Cargo.toml:
[dependencies]
circuitbreaker-rs = "0.1.0"
Basic usage:
use circuitbreaker_rs::{CircuitBreaker, BreakerError, State, DefaultPolicy};
use std::time::Duration;
use std::error::Error;
fn main() {
// Create a circuit breaker with custom settings
let breaker = CircuitBreaker::builder()
.failure_threshold(0.5)
.cooldown(Duration::from_secs(30))
.probe_interval(3)
.build();
// Use the circuit breaker to wrap function calls
match breaker.call(|| external_service_call()) {
Ok(result) => println!("Call succeeded: {:?}", result),
Err(BreakerError::Open) => println!("Circuit is open, call was prevented"),
Err(BreakerError::Operation(err)) => println!("Call failed: {:?}", err),
Err(err) => println!("Other error: {:?}", err),
}
}
// Your function that might fail - must implement std::error::Error
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct MyError(String);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Service error: {}", self.0)
}
}
impl Error for MyError {}
fn external_service_call() -> Result<String, MyError> {
// Actual implementation
Ok("Success".to_string())
// Or for an error: Err(MyError("Service unavailable".to_string()))
}
Important: The error type used with the circuit breaker must implement the std::error::Error trait. Using types like String as errors directly will not work. Here's a simple pattern for creating a compatible error type:
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct MyError(String);
impl MyError {
fn new(msg: &str) -> Self {
MyError(msg.to_string())
}
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "My error: {}", self.0)
}
}
impl Error for MyError {}
The library offers extensive configuration options through the builder pattern:
let breaker = CircuitBreaker::builder()
.failure_threshold(0.5) // Trip when error rate exceeds 50%
.min_throughput(10) // Require at least 10 calls before considering error rate
.cooldown(Duration::from_secs(30)) // Wait 30 seconds before trying half-open state
.probe_interval(3) // Allow 3 test requests when half-open
.consecutive_failures(5) // Trip after 5 consecutive failures regardless of rate
.consecutive_successes(2) // Reset after 2 consecutive successes in half-open state
.metric_sink(prometheus_sink()) // Use Prometheus for metrics
.build();
Implement the BreakerPolicy trait to create custom circuit breaker policies:
use circuitbreaker_rs::{BreakerPolicy, BreakerStats};
struct MyCustomPolicy {
// Your policy configuration
}
impl BreakerPolicy for MyCustomPolicy {
fn should_trip(&self, stats: &BreakerStats) -> bool {
// Your logic to determine when to trip the circuit
stats.consecutive_failures() > 10 && stats.error_rate() > 0.3
}
fn should_reset(&self, stats: &BreakerStats) -> bool {
// Your logic to determine when to reset the circuit
stats.consecutive_successes() >= 5
}
}
Async support is available with the async feature:
[dependencies]
circuitbreaker-rs = { version = "0.1.0", features = ["async"] }
And then use the call_async method:
let breaker = CircuitBreaker::builder().build();
let result = breaker.call_async(|| async {
external_async_service_call().await
}).await;
The library provides hooks for state transitions and metric collection:
let mut hooks = HookRegistry::new();
hooks.set_on_open(|| println!("Circuit opened!"));
hooks.set_on_close(|| println!("Circuit closed!"));
let breaker = CircuitBreaker::builder()
.hooks(hooks)
.metric_sink(MyMetricSink::new())
.build();
std - Standard library support (default)async - Async support with Tokioprometheus - Prometheus metrics integrationtracing - Tracing integrationcircuitbreaker-rs is designed for high-performance scenarios. Here are some benchmark results from the included benchmarks:
| Benchmark | Description | Performance |
|---|---|---|
circuit_breaker_closed_success |
Regular operation (circuit closed) | ~80 ns per call |
circuit_breaker_transition |
State transition performance | ~600 ns per transition |
circuit_breaker_concurrent |
Multi-threaded performance (4 threads) | ~530 μs for 4000 operations |
These benchmarks demonstrate the library's minimal overhead during normal operation and efficient state transitions, making it suitable for high-throughput systems and latency-sensitive applications.
Run the benchmarks yourself with: cargo bench
For full API documentation, visit docs.rs/circuitbreaker-rs.
CircuitBreaker: The main circuit breaker structBreakerBuilder: Builder pattern for constructing a circuit breaker with custom settingsBreakerPolicy: Trait for implementing custom tripping and recovery policiesBreakerError: Error type returned when a call fails or is rejectedState: Enum representing the possible states of the circuit breaker (Closed, Open, HalfOpen)Check the examples directory for more complete examples.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under either of:
at your option.