llm_circuit_breaker/lib.rs
1//! # llm-circuit-breaker
2//!
3//! Tiny circuit breaker for LLM API calls.
4//!
5//! [`llm-retry`](https://crates.io/crates/llm-retry) handles individual
6//! transient failures with backoff. This crate handles the case where
7//! the LLM provider is clearly down for everyone: rather than retry each
8//! call (and pay for it), stop calling for a window and let one probe
9//! through after the window expires.
10//!
11//! ## States
12//!
13//! - `Closed` — calls pass through, failures are counted.
14//! - `Open` — after `failure_threshold` consecutive failures, all calls
15//! reject with `BreakerError::Open` for `reset_timeout`.
16//! - `HalfOpen` — after `reset_timeout` expires, the next call probes.
17//! If it succeeds, the breaker closes. If it fails, the breaker opens
18//! for another `reset_timeout`.
19//!
20//! ## Example
21//!
22//! ```
23//! use llm_circuit_breaker::{CircuitBreaker, BreakerConfig, BreakerError};
24//! use std::time::Duration;
25//!
26//! let cb = CircuitBreaker::new(BreakerConfig {
27//! failure_threshold: 3,
28//! reset_timeout: Duration::from_secs(30),
29//! });
30//!
31//! // first failures are counted
32//! let r: Result<u32, _> = cb.call(|_: &&str| true, || Err("server_error"));
33//! assert!(matches!(r, Err(BreakerError::Inner("server_error"))));
34//!
35//! // after three failures the breaker opens
36//! let _ = cb.call(|_: &&str| true, || Err::<u32, &str>("server_error"));
37//! let _ = cb.call(|_: &&str| true, || Err::<u32, &str>("server_error"));
38//! let r: Result<u32, _> = cb.call(|_: &&str| true, || Ok(42));
39//! assert!(matches!(r, Err(BreakerError::Open)));
40//! ```
41//!
42//! ## Counting policy
43//!
44//! `should_count(&err) -> bool` decides whether a given error counts as
45//! a failure for the breaker. Typically you only count server/throttle
46//! errors and skip caller bugs (4xx, validation). Use the predicates
47//! from `llm-retry` to share the policy.
48
49#![deny(missing_docs)]
50
51mod breaker;
52mod config;
53mod error;
54
55pub use breaker::{BreakerState, CircuitBreaker};
56pub use config::BreakerConfig;
57pub use error::BreakerError;