#breaker #circuit #failure #distributed-systems #error #pattern #state

circuit_breaker

A Rust implementation of the Circuit Breaker pattern for building resilient and fault-tolerant systems

2 releases

0.1.1 Oct 7, 2024
0.1.0 Oct 7, 2024

#11 in #failure

Apache-2.0

18KB
168 lines

Circuit Breaker

A robust Rust implementation of the Circuit Breaker pattern, designed to prevent cascading failures in distributed systems and improve system resilience.

Features

  • Three-state circuit breaker: Closed, Open, and Half-Open
  • Configurable failure threshold and reset timeout
  • Thread-safe implementation using Arc and Mutex
  • Customizable callback functions for state transitions
  • Automatic state transition from Open to Half-Open after reset timeout
  • Comprehensive error handling and custom error types
  • Designed for easy integration into existing Rust projects

Table of Contents

  1. Installation
  2. Usage
  3. API Reference
  4. Circuit Breaker States
  5. Configuration
  6. Error Handling
  7. Thread Safety
  8. Examples
  9. Testing
  10. Contributing
  11. License

Installation

Add this to your Cargo.toml:

[dependencies]
circuit_breaker = "0.1.0"

Usage

Here's a basic example of how to use the Circuit Breaker:

use circuit_breaker::{CircuitBreaker, CircuitState};
use std::time::Duration;
fn main() {
// Create a new CircuitBreaker with a failure threshold of 3 and a reset timeout of 60 seconds
let cb = CircuitBreaker::new(3, Duration::from_secs(60));
// Set up callbacks for state transitions
cb.set_on_open(|| println!("Circuit opened!"));
cb.set_on_close(|| println!("Circuit closed!"));
cb.set_on_half_open(|| println!("Circuit is half-open!"));
// Execute an operation through the circuit breaker
for in 0..5 {
match cb.execute(|| {
// Simulating an operation that might fail
if rand::random::<f32>() < 0.5 {
Ok("Operation successful")
} else {
Err(std::io::Error::new(std::io::ErrorKind::Other, "Operation failed"))
}
}) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
println!("Current state: {:?}", cb.state());
}
}

API Reference

CircuitBreaker

  • new(failure_threshold: u32, reset_timeout: Duration) -> Self Creates a new CircuitBreaker instance.

  • execute<F, T, E>(&self, f: F) -> Result<T, Box<dyn std::error::Error>> Executes the given function within the circuit breaker context.

  • state(&self) -> CircuitState Returns the current state of the circuit breaker.

  • handle_failure(&self) Manually records a failure, potentially opening the circuit.

  • handle_success(&self) Manually records a success, potentially closing the circuit if it was half-open.

  • set_on_open<F>(&self, callback: F) Sets a callback function to be executed when the circuit opens.

  • set_on_close<F>(&self, callback: F) Sets a callback function to be executed when the circuit closes.

  • set_on_half_open<F>(&self, callback: F) Sets a callback function to be executed when the circuit transitions to half-open.

CircuitState

An enum representing the possible states of the circuit breaker:

  • Closed: The circuit is closed and allowing requests to pass through.
  • Open: The circuit is open and blocking requests.
  • HalfOpen: The circuit is allowing a limited number of requests to test if the system has recovered.

Circuit Breaker States

  1. Closed: In this state, all requests are allowed to pass through. The circuit breaker keeps track of the number of failures.

  2. Open: When the number of failures exceeds the threshold, the circuit breaker trips and enters the Open state. In this state, all requests are immediately rejected without calling the protected function.

  3. Half-Open: After the reset timeout has elapsed, the circuit breaker enters the Half-Open state. In this state, a limited number of requests are allowed through to test if the system has recovered.

Configuration

The CircuitBreaker can be configured with two main parameters:

  1. failure_threshold: The number of consecutive failures that will cause the circuit to open.
  2. reset_timeout: The duration after which the circuit will transition from Open to Half-Open.

Error Handling

The circuit breaker uses a custom CircuitBreakerError type to represent errors specific to its operation. When the circuit is open, execute() will return a CircuitBreakerError::CircuitOpen error.

Thread Safety

The CircuitBreaker is designed to be thread-safe and can be safely shared between multiple threads. It uses Arc and Mutex internally to ensure safe concurrent access.

Examples

Basic Usage

use circuit_breaker::CircuitBreaker;
use std::time::Duration;
let cb = CircuitBreaker::new(3, Duration::from_secs(60));
match cb.execute(|| {
// Your potentially failing operation here
Ok::<, std::io::Error>("Success")
}) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}

With Callbacks

use circuit_breaker::CircuitBreaker;
use std::time::Duration;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
let cb = CircuitBreaker::new(3, Duration::from_secs(60));
let open_count = Arc::new(AtomicUsize::new(0));
let open_count_clone = open_count.clone();
cb.set_on_open(move || {
open_count_clone.fetch_add(1, Ordering::SeqCst);
println!("Circuit opened!");
});

// Similar setup for on_close and on_half_open callbacks

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the Apache-2.0 License - see the LICENSE file for details.

No runtime deps