Async Programming Model
Async-First Philosophy
cache-kit is built from the ground up as an async-first library. This design choice reflects the reality of modern Rust services where:
- Database queries are async (SQLx, SeaORM, tokio-postgres)
- HTTP handlers are async (Axum, Actix, warp)
- gRPC services are async (tonic)
- Background workers are async (tokio, async-std)
The cache layer sits between these components and must integrate seamlessly with async workflows.
Tokio Runtime Integration
cache-kit is designed for tokio-based applications. The library does not:
- Spawn its own runtime
- Require a specific runtime configuration
- Impose threading models on your application
Instead, cache-kit operates within your existing tokio runtime.
Runtime Requirements
[dependencies]
tokio = { version = "1.41", features = ["rt", "sync", "macros"] }
cache-kit = "0.9"
The minimum required tokio features:
rt— Runtime supportsync— Synchronization primitives (Arc, Mutex, RwLock)macros—#[tokio::main]attribute macro
Interaction Model
The typical interaction flow follows this pattern:
Async Database → Async Cache → Async Application
All cache operations work seamlessly within async contexts. For detailed ORM integration examples (SQLx, SeaORM, Diesel), see Database & ORM Compatibility.
Why DataRepository is Async
The DataRepository trait uses async methods:
pub trait DataRepository<T: CacheEntity>: Send + Sync {
async fn fetch_by_id(&self, id: &T::Key) -> Result<Option<T>>;
}
This design is intentional and provides several benefits:
- Native async support — Aligns with modern Rust practices and integrates seamlessly with async databases
- Flexibility — Works with both sync and async database layers (see Database Compatibility for Diesel example using
spawn_blocking) - Backend compatibility — Cache backends (Redis, Memcached) are inherently async
Recommended async databases:
- SQLx — Async, compile-time checked SQL
- SeaORM — Async ORM for Rust
- tokio-postgres — Pure async PostgreSQL client
For detailed repository implementation examples, see Database & ORM Compatibility.
⚠️ NEVER use block_in_place + block_on
NEVER use block_in_place + Handle::current().block_on() — this pattern is incorrect. Always use async fn with .await for async databases. For synchronous ORMs like Diesel, use tokio::task::spawn_blocking (see Database Compatibility for examples).
Async Cache Backends
Cache backends are fully async and follow the same initialization pattern:
// Redis
use cache_kit::backend::{RedisBackend, RedisConfig};
let config = RedisConfig::default(); // Uses localhost:6379
let backend = RedisBackend::new(config).await?;
// Memcached
use cache_kit::backend::{MemcachedBackend, MemcachedConfig};
let config = MemcachedConfig { servers: vec!["localhost:11211".to_string()], ..Default::default() };
let backend = MemcachedBackend::new(config)?;
// InMemory (lock-free via DashMap)
use cache_kit::backend::InMemoryBackend;
let backend = InMemoryBackend::new();
// All use the same expander API
let mut expander = CacheExpander::new(backend);
All backends work seamlessly within your async context — no special handling required.
Runtime Choice is Yours
cache-kit does not:
- Require a specific tokio runtime configuration
- Spawn background tasks (no
tokio::spawncalls) - Create thread pools
- Impose executor choices
You control:
- Runtime flavor (multi-thread, current-thread)
- Worker thread count
- Task spawning strategy
- Shutdown behavior
Best Practices
DO
- ✅ Use
tokio::mainfor your application entry point - ✅ Make
DataRepository::fetch_by_idan async function - ✅ Use async database drivers (SQLx, SeaORM, tokio-postgres)
- ✅ Let cache-kit operate within your existing runtime
- ✅ Keep async boundaries explicit and clear
DON’T
- ❌ Use
block_in_place+block_on(incorrect pattern) - ❌ Call
block_oninside async contexts - ❌ Create multiple tokio runtimes unnecessarily
- ❌ Assume cache-kit manages runtime lifecycle
Example: Full Async Service
For complete working examples of tokio-based services using cache-kit with async operations:
- examples/actixsqlx — Actix Web integration with SQLx, async database operations, and cache-kit’s async API
- examples/actixsqlx/src/services/user_service.rs — Service layer implementation with caching
Next Steps
- Learn about Core Concepts in cache-kit
- Explore Database & ORM Compatibility for detailed ORM integration examples
- Review API Frameworks for framework-specific integration patterns