Moka Cache TTL In Memory

Cache expensive computations with moka in Rust, combining TTL expiry with maximum size, entry metrics, and async loading.

RustData Fetching

Code

snippet
use moka::future::Cache;
use std::time::Duration;

#[derive(Debug, Clone)]
struct ExchangeRates {
    base: String,
    rates: Vec<(String, f64)>,
}

async fn fetch_rates(base: &str) -> ExchangeRates {
    // 模拟外部 API 的网络往返
    tokio::time::sleep(Duration::from_millis(50)).await;
    ExchangeRates {
        base: base.into(),
        rates: vec![
            ("usd".into(), 1.0),
            ("eur".into(), 0.92),
            ("jpy".into(), 149.6),
        ],
    }
}

fn build_cache() -> Cache<String, ExchangeRates> {
    Cache::builder()
        .time_to_live(Duration::from_secs(30)) // 条目级 TTL
        .max_capacity(10_000)
        .weigher(|_key, value: &ExchangeRates| -> u32 {
            value.rates.len() as u32
        })
        .build()
}

#[tokio::main]
async fn main() {
    let cache = build_cache();

    // 手动模式:先查后填
    if let Some(hit) = cache.get("base-eur").await {
        println!("cache hit: {:?} entries", hit.rates.len());
    } else {
        let fresh = fetch_rates("eur").await;
        cache.insert("base-eur".into(), fresh).await;
        println!("cache miss: loaded and inserted");
    }

    // 自动加载模式:未命中时原子执行加载器
    let auto = Cache::builder()
        .time_to_live(Duration::from_secs(60))
        .build();

    let rates = auto
        .try_get_with(
            "base-jpy",
            fetch_rates("jpy"),
        )
        .await
        .expect("loader should not fail");

    println!("auto-loaded {} rates for {}", rates.rates.len(), rates.base);

    println!("entry count: {}", auto.entry_count());
    println!("cached weight: {}", auto.weighted_size());
}