Skip to content

Commit b854f43

Browse files
authored
Merge pull request #97 from Tuntii/docs-update-resilience-4393523194836872208
docs: Update versions and add Resilience Patterns recipe
2 parents e21a057 + 7f18d9d commit b854f43

File tree

6 files changed

+130
-4
lines changed

6 files changed

+130
-4
lines changed

crates/rustapi-extras/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
//!
3737
//! ```toml
3838
//! [dependencies]
39-
//! rustapi-extras = { version = "0.1", features = ["jwt", "cors", "csrf"] }
39+
//! rustapi-extras = { version = "0.1.275", features = ["jwt", "cors", "csrf"] }
4040
//! ```
4141
4242
#![warn(missing_docs)]

crates/rustapi-rs/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
//!
5555
//! ```toml
5656
//! [dependencies]
57-
//! rustapi-rs = { version = "0.1", features = ["jwt", "cors"] }
57+
//! rustapi-rs = { version = "0.1.275", features = ["jwt", "cors"] }
5858
//! ```
5959
6060
// Re-export core functionality

crates/rustapi-toon/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//!
3131
//! ```toml
3232
//! [dependencies]
33-
//! rustapi-rs = { version = "0.1", features = ["toon"] }
33+
//! rustapi-rs = { version = "0.1.275", features = ["toon"] }
3434
//! ```
3535
//!
3636
//! ### Toon Extractor

docs/cookbook/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- [Custom Middleware](recipes/custom_middleware.md)
3636
- [Real-time Chat](recipes/websockets.md)
3737
- [Production Tuning](recipes/high_performance.md)
38+
- [Resilience Patterns](recipes/resilience.md)
3839
- [Deployment](recipes/deployment.md)
3940
- [HTTP/3 (QUIC)](recipes/http3_quic.md)
4041
- [Automatic Status Page](recipes/status_page.md)

docs/cookbook/src/learning/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,15 @@ Build robust, observable, and secure systems.
117117
| Step | Feature | Description |
118118
|------|---------|-------------|
119119
| 1 | **Observability** | Set up [OpenTelemetry and Structured Logging](../crates/rustapi_extras.md#observability) |
120-
| 2 | **Resilience** | Implement [Circuit Breakers and Retries](../crates/rustapi_extras.md#resilience) |
120+
| 2 | **Resilience** | Implement [Circuit Breakers and Retries](../recipes/resilience.md) |
121121
| 3 | **Advanced Security** | Add [OAuth2 and Security Headers](../crates/rustapi_extras.md#advanced-security) |
122122
| 4 | **Optimization** | Configure [Caching and Deduplication](../crates/rustapi_extras.md#optimization) |
123123
| 5 | **Background Jobs** | Implement [Reliable Job Queues](../crates/rustapi_jobs.md) |
124124

125125
**Related Cookbook Recipes:**
126126
- [rustapi-extras: The Toolbox](../crates/rustapi_extras.md)
127127
- [rustapi-jobs: The Workhorse](../crates/rustapi_jobs.md)
128+
- [Resilience Patterns](../recipes/resilience.md)
128129

129130
---
130131

@@ -242,6 +243,7 @@ Each example includes:
242243
| [Custom Middleware](../recipes/custom_middleware.md) | `middleware-chain` |
243244
| [Real-time Chat](../recipes/websockets.md) | `websocket` |
244245
| [Production Tuning](../recipes/high_performance.md) | `microservices-advanced` |
246+
| [Resilience Patterns](../recipes/resilience.md) | `microservices` |
245247
| [Deployment](../recipes/deployment.md) | `serverless-lambda` |
246248

247249
---
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Resilience Patterns
2+
3+
Building robust applications requires handling failures gracefully. RustAPI provides a suite of middleware to help your service survive partial outages, latency spikes, and transient errors.
4+
5+
These patterns are essential for the "Enterprise Platform" learning path and microservices architectures.
6+
7+
## Prerequisites
8+
9+
Add the resilience features to your `Cargo.toml`. For example:
10+
11+
```toml
12+
[dependencies]
13+
rustapi-rs = { version = "0.1.275", features = ["full"] }
14+
# OR cherry-pick features
15+
# rustapi-extras = { version = "0.1.275", features = ["circuit-breaker", "retry", "timeout"] }
16+
```
17+
18+
## Circuit Breaker
19+
20+
The Circuit Breaker pattern prevents your application from repeatedly trying to execute an operation that's likely to fail. It gives the failing service time to recover.
21+
22+
### How it works
23+
1. **Closed**: Requests flow normally.
24+
2. **Open**: After `failure_threshold` is reached, requests fail immediately with `503 Service Unavailable`.
25+
3. **Half-Open**: After `timeout` passes, a limited number of test requests are allowed. If they succeed, the circuit closes.
26+
27+
### Usage
28+
29+
```rust
30+
use rustapi_rs::prelude::*;
31+
use rustapi_extras::circuit_breaker::CircuitBreakerLayer;
32+
use std::time::Duration;
33+
34+
fn main() {
35+
let app = RustApi::new()
36+
.layer(
37+
CircuitBreakerLayer::new()
38+
.failure_threshold(5) // Open after 5 failures
39+
.timeout(Duration::from_secs(30)) // Wait 30s before retrying
40+
.success_threshold(2) // Require 2 successes to close
41+
)
42+
.route("/", get(handler));
43+
44+
// ... run app
45+
}
46+
```
47+
48+
## Retry with Backoff
49+
50+
Transient failures (network blips, temporary timeouts) can often be resolved by simply retrying the request. The `RetryLayer` handles this automatically with configurable backoff strategies.
51+
52+
### Strategies
53+
- **Exponential**: `base * 2^attempt` (Recommended for most cases)
54+
- **Linear**: `base * attempt`
55+
- **Fixed**: Constant delay
56+
57+
### Usage
58+
59+
```rust
60+
use rustapi_rs::prelude::*;
61+
use rustapi_extras::retry::{RetryLayer, RetryStrategy};
62+
use std::time::Duration;
63+
64+
fn main() {
65+
let app = RustApi::new()
66+
.layer(
67+
RetryLayer::new()
68+
.max_attempts(3)
69+
.initial_backoff(Duration::from_millis(100))
70+
.max_backoff(Duration::from_secs(5))
71+
.strategy(RetryStrategy::Exponential)
72+
.retryable_statuses(vec![500, 502, 503, 504, 429])
73+
)
74+
.route("/", get(handler));
75+
76+
// ... run app
77+
}
78+
```
79+
80+
> **Warning**: Be careful when combining Retries with non-idempotent operations (like `POST` requests that charge a credit card). The middleware safely handles cloning requests, but your business logic must support it.
81+
82+
## Timeouts
83+
84+
Never let a request hang indefinitely. The `TimeoutLayer` enforces a hard limit on request duration, returning `408 Request Timeout` if exceeded.
85+
86+
### Usage
87+
88+
```rust
89+
use rustapi_rs::prelude::*;
90+
use rustapi_extras::timeout::TimeoutLayer;
91+
use std::time::Duration;
92+
93+
fn main() {
94+
let app = RustApi::new()
95+
// Fail if handler takes longer than 5 seconds
96+
.layer(TimeoutLayer::from_secs(5))
97+
.route("/", get(slow_handler));
98+
99+
// ... run app
100+
}
101+
```
102+
103+
## Combining Layers (The Resilience Stack)
104+
105+
Order matters! Timeout should be the "outermost" constraint, followed by Circuit Breaker, then Retry.
106+
107+
In RustAPI (Tower) middleware, layers wrap around each other. The order you call `.layer()` wraps the *previous* service.
108+
109+
**Recommended Order:**
110+
1. **Retry** (Inner): Retries specific failures from the handler.
111+
2. **Circuit Breaker** (Middle): Stops retrying if the system is overloaded.
112+
3. **Timeout** (Outer): Enforces global time limit including all retries.
113+
114+
```rust
115+
let app = RustApi::new()
116+
// 1. Retry (handles transient errors)
117+
.layer(RetryLayer::new())
118+
// 2. Circuit Breaker (protects upstream)
119+
.layer(CircuitBreakerLayer::new())
120+
// 3. Timeout (applies to the whole operation)
121+
.layer(TimeoutLayer::from_secs(10))
122+
.route("/", get(handler));
123+
```

0 commit comments

Comments
 (0)