Expand description
Composable resilience and fault-tolerance middleware for Tower services.
tower-resilience provides a collection of resilience patterns inspired by
Resilience4j. Each pattern is available as both an
individual crate and as a feature in this meta-crate.
§Quick Start
[dependencies]
tower-resilience = { version = "0.7", features = ["circuitbreaker", "bulkhead"] }§Presets: Get Started Immediately
Every pattern includes preset configurations with sensible defaults. Start immediately without tuning parameters - customize later when needed:
use tower_resilience::retry::RetryLayer;
use tower_resilience::circuitbreaker::CircuitBreakerLayer;
use tower_resilience::ratelimiter::RateLimiterLayer;
use tower_resilience::bulkhead::BulkheadLayer;
// Retry: 3 attempts with 100ms exponential backoff
let retry = RetryLayer::<(), MyError>::exponential_backoff().build();
// Circuit breaker: balanced defaults (50% threshold, 100 call window)
let breaker = CircuitBreakerLayer::standard().build();
// Rate limiter: 100 requests per second
let limiter = RateLimiterLayer::per_second(100).build();
// Bulkhead: 50 concurrent calls
let bulkhead = BulkheadLayer::medium().build();§Available Presets
| Pattern | Presets |
|---|---|
| Retry | exponential_backoff(), aggressive(), conservative() |
| Circuit Breaker | standard(), fast_fail(), tolerant() |
| Rate Limiter | per_second(n), per_minute(n), burst(rate, size) |
| Bulkhead | small(), medium(), large() |
Presets return builders, so you can customize any setting:
use tower_resilience::circuitbreaker::CircuitBreakerLayer;
use std::time::Duration;
let breaker = CircuitBreakerLayer::fast_fail()
.name("payment-api")
.wait_duration_in_open(Duration::from_secs(30))
.build();§Resilience Patterns
- Circuit Breaker - Prevents cascading failures by stopping calls to failing services
- Bulkhead - Isolates resources to prevent system-wide failures
- Time Limiter - Advanced timeout handling with cancellation support
- Retry - Intelligent retry with exponential backoff and jitter
- Rate Limiter - Controls request rate to protect services
- Cache - Response memoization to reduce load
- Reconnect - Automatic reconnection with configurable backoff strategies
- Health Check - Proactive health monitoring with intelligent resource selection
- Fallback - Provides alternative responses when services fail
- Hedge - Reduces tail latency by firing parallel requests
- Executor - Delegates request processing to dedicated executors
- Adaptive - Dynamic concurrency limiting using AIMD or Vegas algorithms
- Coalesce - Deduplicates concurrent identical requests (singleflight)
§Documentation Guides
§Getting Started
- Tower Primer - Introduction to Tower concepts (Service, Layer, composition)
- Pattern Guides - Detailed guides for each pattern with examples and anti-patterns
- Composition Guide - How to combine patterns effectively
- Use Cases - Real-world scenarios and recommendations
§Observability
- Metrics - Prometheus metrics for all patterns
- Tracing - Structured logging setup
- Events - Custom event listeners
§Example
use tower::{ServiceBuilder, Layer};
use tower_resilience::circuitbreaker::CircuitBreakerLayer;
use tower_resilience::retry::RetryLayer;
use std::time::Duration;
// Build a resilient HTTP client
let circuit_breaker = CircuitBreakerLayer::builder()
.name("api-client")
.failure_rate_threshold(0.5)
.sliding_window_size(100)
.build();
let retry = RetryLayer::<(), MyError>::builder()
.name("api-retry")
.max_attempts(3)
.exponential_backoff(Duration::from_millis(100))
.build();
// Compose manually for reliability
let resilient_client = retry.layer(http_client);
let resilient_client = circuit_breaker.layer(resilient_client);§Performance
All patterns have low overhead in the happy path:
- Retry: ~80-100ns (lightest)
- Time Limiter: ~107ns
- Rate Limiter: ~124ns
- Bulkhead: ~162ns
- Cache (hit): ~250ns
- Circuit Breaker: ~298ns (heaviest)
See benchmarks for detailed measurements.
§Error Handling
When composing multiple resilience layers, each layer has its own error type.
core::ResilienceError<E> unifies these into a single error type, eliminating
boilerplate From implementations.
§Quick Setup
use tower_resilience_core::ResilienceError;
// Your application error
#[derive(Debug, Clone)]
enum AppError {
DatabaseDown,
InvalidRequest,
}
impl std::fmt::Display for AppError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AppError::DatabaseDown => write!(f, "Database down"),
AppError::InvalidRequest => write!(f, "Invalid request"),
}
}
}
impl std::error::Error for AppError {}
// Use ResilienceError as your service error type - zero From impls needed!
type ServiceError = ResilienceError<AppError>;§Pattern Matching
use tower_resilience_core::ResilienceError;
fn handle_error(error: ResilienceError<AppError>) {
match error {
ResilienceError::Timeout { layer } => {
eprintln!("Timeout in {}", layer);
}
ResilienceError::CircuitOpen { name } => {
eprintln!("Circuit breaker {:?} is open", name);
}
ResilienceError::BulkheadFull { concurrent_calls, max_concurrent } => {
eprintln!("Bulkhead full: {}/{}", concurrent_calls, max_concurrent);
}
ResilienceError::RateLimited { retry_after } => {
eprintln!("Rate limited, retry after {:?}", retry_after);
}
ResilienceError::Application(app_err) => {
eprintln!("Application error: {}", app_err);
}
}
}§Helper Methods
// Quickly check error categories
if error.is_timeout() {
// Handle timeout from TimeLimiter or Bulkhead
} else if error.is_circuit_open() {
// Circuit breaker protecting the system
} else if error.is_rate_limited() {
// Backpressure - slow down
} else if error.is_application() {
// Extract the underlying application error
let app_err = error.application_error();
}For complete documentation, see core::ResilienceError.
Re-exports§
pub use tower_resilience_core as core;
Modules§
- composition
- Composition Guide
- observability
- Observability guide for tower-resilience.
- patterns
- Pattern Guides
- tower_
primer - Tower Primer
- use_
cases - Use Cases