multi_tier_cache/lib.rs
1//! Multi-Tier Cache
2//!
3//! A high-performance, production-ready multi-tier caching library for Rust featuring:
4//! - **L1 Cache**: In-memory caching with Moka (sub-millisecond latency)
5//! - **L2 Cache**: Distributed caching with Redis (persistent storage)
6//! - **Cache Stampede Protection**: `DashMap` + Mutex request coalescing
7//! - **Redis Streams**: Built-in support for event streaming
8//! - **Automatic L2-to-L1 Promotion**: Intelligent cache tier promotion
9//! - **Comprehensive Statistics**: Hit rates, promotions, in-flight tracking
10//!
11//! # Quick Start
12//!
13//! ```rust,no_run
14//! use multi_tier_cache::{CacheSystem, CacheStrategy};
15//!
16//! #[tokio::main]
17//! async fn main() -> anyhow::Result<()> {
18//! // Initialize cache system
19//! let cache = CacheSystem::new().await?;
20//!
21//! // Store data with cache strategy
22//! let data = serde_json::json!({"user": "alice", "score": 100});
23//! cache.cache_manager()
24//! .set_with_strategy("user:1", data, CacheStrategy::ShortTerm)
25//! .await?;
26//!
27//! // Retrieve data (L1 first, then L2 fallback)
28//! if let Some(cached) = cache.cache_manager().get("user:1").await? {
29//! tracing::info!("Cached data: {}", cached);
30//! }
31//!
32//! // Get statistics
33//! let stats = cache.cache_manager().get_stats();
34//! tracing::info!("Hit rate: {:.2}%", stats.hit_rate);
35//!
36//! Ok(())
37//! }
38//! ```
39//!
40//! # Features
41//!
42//! - **Multi-Tier Architecture**: Combines fast in-memory (L1) with persistent distributed (L2) caching
43//! - **Cache Stampede Protection**: Prevents duplicate computations during cache misses
44//! - **Redis Streams**: Publish/subscribe with automatic trimming
45//! - **Zero-Config**: Sensible defaults, works out of the box
46//! - **Production-Proven**: Battle-tested at 16,829+ RPS with 5.2ms latency
47//!
48//! # Architecture
49//!
50//! ```text
51//! Request → L1 Cache (Moka) → L2 Cache (Redis) → Compute/Fetch
52//! ↓ Hit (90%) ↓ Hit (75%) ↓ Miss (5%)
53//! Return Promote to L1 Store in L1+L2
54//! ```
55
56use anyhow::Result;
57use std::sync::Arc;
58use tracing::{info, warn};
59
60pub mod backends;
61pub mod builder;
62pub mod cache_manager;
63pub mod invalidation;
64pub mod redis_streams;
65pub mod traits;
66
67// Re-export backend types (maintains backward compatibility)
68pub use backends::{
69 DashMapCache, // Additional backends
70 L1Cache,
71 L2Cache, // Type aliases
72 MokaCache,
73 RedisCache, // Default backends
74};
75
76// Optional backends (feature-gated)
77#[cfg(feature = "backend-memcached")]
78pub use backends::MemcachedCache;
79
80#[cfg(feature = "backend-quickcache")]
81pub use backends::QuickCacheBackend;
82pub use builder::CacheSystemBuilder;
83pub use cache_manager::{
84 CacheManager,
85 CacheManagerStats,
86 CacheStrategy,
87 CacheTier,
88 // Multi-tier support (v0.5.0+)
89 TierConfig,
90 TierStats,
91};
92pub use invalidation::{
93 InvalidationConfig, InvalidationMessage, InvalidationPublisher, InvalidationStats,
94 InvalidationSubscriber,
95};
96pub use redis_streams::RedisStreams;
97pub use traits::{CacheBackend, L2CacheBackend, StreamingBackend};
98
99// Re-export async_trait for user convenience
100pub use async_trait::async_trait;
101
102/// Main entry point for the Multi-Tier Cache system
103///
104/// Provides unified access to L1 (Moka) and L2 (Redis) caches with
105/// automatic failover, promotion, and stampede protection.
106///
107/// # Example
108///
109/// ```rust,no_run
110/// use multi_tier_cache::CacheSystem;
111///
112/// #[tokio::main]
113/// async fn main() -> anyhow::Result<()> {
114/// let cache = CacheSystem::new().await?;
115///
116/// // Use cache_manager for all operations
117/// let manager = cache.cache_manager();
118///
119/// Ok(())
120/// }
121/// ```
122///
123/// # Note on `l1_cache` and `l2_cache` Fields
124///
125/// When using multi-tier mode or custom backends, `l1_cache` and `l2_cache`
126/// may be `None`. Always use `cache_manager()` for cache operations.
127#[derive(Clone)]
128pub struct CacheSystem {
129 /// Unified cache manager (primary interface)
130 pub cache_manager: Arc<CacheManager>,
131 /// L1 Cache (in-memory, Moka) - `None` when using custom backends
132 pub l1_cache: Option<Arc<L1Cache>>,
133 /// L2 Cache (distributed, Redis) - `None` when using custom backends
134 pub l2_cache: Option<Arc<L2Cache>>,
135}
136
137impl CacheSystem {
138 /// Create new cache system with default configuration
139 ///
140 /// # Configuration
141 ///
142 /// Redis connection is configured via `REDIS_URL` environment variable.
143 /// Default: `redis://127.0.0.1:6379`
144 ///
145 /// # Example
146 ///
147 /// ```rust,no_run
148 /// use multi_tier_cache::CacheSystem;
149 ///
150 /// #[tokio::main]
151 /// async fn main() -> anyhow::Result<()> {
152 /// // Set environment variable (optional)
153 /// std::env::set_var("REDIS_URL", "redis://localhost:6379");
154 ///
155 /// let cache = CacheSystem::new().await?;
156 /// Ok(())
157 /// }
158 /// ```
159 /// # Errors
160 ///
161 /// Returns an error if cache initialization fails.
162 pub async fn new() -> Result<Self> {
163 info!("Initializing Multi-Tier Cache System");
164
165 // Initialize L1 cache (Moka)
166 let l1_cache = Arc::new(L1Cache::new()?);
167
168 // Initialize L2 cache (Redis)
169 let l2_cache = Arc::new(L2Cache::new().await?);
170
171 // Initialize cache manager
172 let cache_manager = Arc::new(CacheManager::new(l1_cache.clone(), l2_cache.clone()).await?);
173
174 info!("Multi-Tier Cache System initialized successfully");
175
176 Ok(Self {
177 cache_manager,
178 l1_cache: Some(l1_cache),
179 l2_cache: Some(l2_cache),
180 })
181 }
182
183 /// Create cache system with custom Redis URL
184 ///
185 /// # Arguments
186 ///
187 /// * `redis_url` - Redis connection string (e.g., `<redis://localhost:6379>`)
188 ///
189 /// # Example
190 ///
191 /// ```rust,no_run
192 /// use multi_tier_cache::CacheSystem;
193 ///
194 /// #[tokio::main]
195 /// async fn main() -> anyhow::Result<()> {
196 /// let cache = CacheSystem::with_redis_url("redis://custom:6379").await?;
197 /// Ok(())
198 /// }
199 /// ```
200 /// # Errors
201 ///
202 /// Returns an error if cache initialization fails.
203 pub async fn with_redis_url(redis_url: &str) -> Result<Self> {
204 info!(redis_url = %redis_url, "Initializing Multi-Tier Cache System with custom Redis URL");
205
206 // Initialize L1 cache (Moka)
207 let l1_cache = Arc::new(L1Cache::new()?);
208
209 // Initialize L2 cache (Redis) with custom URL
210 let l2_cache = Arc::new(L2Cache::with_url(redis_url).await?);
211
212 // Initialize cache manager
213 let cache_manager =
214 Arc::new(CacheManager::new(Arc::clone(&l1_cache), Arc::clone(&l2_cache)).await?);
215
216 info!("Multi-Tier Cache System initialized successfully");
217
218 Ok(Self {
219 cache_manager,
220 l1_cache: Some(l1_cache),
221 l2_cache: Some(l2_cache),
222 })
223 }
224
225 /// Perform health check on all cache tiers
226 ///
227 /// Returns `true` if at least L1 is operational.
228 /// L2 failure is tolerated (graceful degradation).
229 ///
230 /// # Example
231 ///
232 /// ```rust,no_run
233 /// use multi_tier_cache::CacheSystem;
234 ///
235 /// #[tokio::main]
236 /// async fn main() -> anyhow::Result<()> {
237 /// let cache = CacheSystem::new().await?;
238 ///
239 /// if cache.health_check().await {
240 /// tracing::info!("Cache system healthy");
241 /// }
242 ///
243 /// Ok(())
244 /// }
245 /// ```
246 pub async fn health_check(&self) -> bool {
247 let l1_ok = match &self.l1_cache {
248 Some(cache) => cache.health_check().await,
249 None => true, // If no L1 cache instance, assume OK (using custom backends)
250 };
251
252 let l2_ok = match &self.l2_cache {
253 Some(cache) => cache.health_check().await,
254 None => true, // If no L2 cache instance, assume OK (using custom backends)
255 };
256
257 if l1_ok && l2_ok {
258 info!("Multi-Tier Cache health check passed");
259 true
260 } else {
261 warn!(l1_ok = %l1_ok, l2_ok = %l2_ok, "Multi-Tier Cache health check - partial failure");
262 l1_ok // At minimum, L1 should work
263 }
264 }
265
266 /// Get reference to cache manager (primary interface)
267 ///
268 /// Use this for all cache operations: get, set, streams, etc.
269 #[must_use]
270 pub fn cache_manager(&self) -> &Arc<CacheManager> {
271 &self.cache_manager
272 }
273}