foyer
foyer is a hybrid in-memory + disk cache that provides configurable eviction strategies, optional disk storage, request deduplication, and Tokio-native async operations. The http-cache implementation provides traditional buffered caching capabilities using the FoyerManager.
Getting Started
The foyer backend cache manager is available when the manager-foyer feature is enabled.
[dependencies]
http-cache = { version = "1.0", features = ["manager-foyer"] }
Basic Usage
In-Memory Only Cache
For a simple memory-only cache:
use http_cache::FoyerManager; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Create an in-memory cache with capacity for 1000 entries let manager = FoyerManager::in_memory(1000).await?; Ok(()) }
Hybrid Cache (Memory + Disk)
For a hybrid cache with both memory and disk storage:
use http_cache::FoyerManager; use foyer::{HybridCacheBuilder, Engine}; use std::path::PathBuf; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Build a hybrid cache with memory and disk storage let cache = HybridCacheBuilder::new() .memory(64) // Memory capacity in entries .storage(Engine::Large) .with_device_options( foyer::DirectFsDeviceOptionsBuilder::new(PathBuf::from("./cache")) .with_capacity(256 * 1024 * 1024) // 256 MB disk capacity .build() ) .build() .await?; let manager = FoyerManager::new(cache); Ok(()) }
Features
- Hybrid Storage: Combine fast in-memory caching with persistent disk storage
- Configurable Eviction: Support for w-TinyLFU, S3-FIFO, and SIEVE eviction strategies
- Request Deduplication: Automatic deduplication of concurrent requests for the same key
- Tokio-Native: Built for async Rust with native Tokio support
Working with the Manager Directly
Creating a Manager
#![allow(unused)] fn main() { use http_cache::FoyerManager; use foyer::HybridCacheBuilder; // In-memory only (simple) let manager = FoyerManager::in_memory(1000).await?; // Or with custom configuration let cache = HybridCacheBuilder::new() .memory(100) .storage(foyer::Engine::Large) .build() .await?; let manager = FoyerManager::new(cache); }
Cache Operations
The FoyerManager implements the CacheManager trait:
#![allow(unused)] fn main() { use http_cache::{CacheManager, HttpResponse, HttpVersion}; use http_cache_semantics::CachePolicy; use url::Url; // Retrieve a cached response let response = manager.get("my-cache-key").await?; // Store a response in the cache let url = Url::parse("http://example.com")?; let response = HttpResponse { body: b"response body".to_vec(), headers: Default::default(), status: 200, url: url.clone(), version: HttpVersion::Http11, }; let req = http::Request::get("http://example.com").body(())?; let res = http::Response::builder() .status(200) .body(b"response body".to_vec())?; let policy = CachePolicy::new(&req, &res); let cached = manager.put("my-cache-key".into(), response, policy).await?; // Remove from cache manager.delete("my-cache-key").await?; }
Graceful Shutdown
When using disk storage, call close() before application exit to ensure data is flushed:
#![allow(unused)] fn main() { // Before application exit manager.close().await?; }
When to Use Foyer
FoyerManager is ideal for:
- Large Caches: When you need both in-memory speed and disk persistence
- Configurable Eviction: When you need fine-grained control over eviction policies
- High Concurrency: When you have many concurrent requests for the same resources
- Persistence: When cached data should survive application restarts
For simpler use cases, consider:
CACacheManagerfor disk-only cachingMokaManagerfor memory-only caching with simple configurationQuickManagerfor lightweight in-memory caching