moka-cache 是一个基于 moka 的轻量级 K-V 缓存工具库。
它对 moka::sync::Cache 做了一层简单封装,提供了:
- 统一的过期时间模型
Expiration - 基于
serde+bincode的泛型对象缓存 - 可选的缓存移除/过期回调
- 常用缓存操作,如
insert、get、remove、refresh
这个 crate 适合需要在 Rust 项目中快速缓存字符串、数字、字节数组或结构体数据的场景。
- 基于
moka::sync::Cache - 支持缓存任意实现了
Serialize/DeserializeOwned的类型 - 支持多种 TTL:
NeverMillis(u64)Second(u64)Minute(u64)Hour(u64)
- 支持通过回调监听缓存项被移除的原因
- 提供手动刷新 TTL 的
refresh
cargo add moka-cacheuse moka::notification::RemovalCause;
use moka_cache::{Expiration, MokaCache, MokaCacheData};
use std::sync::Arc;
fn on_remove(key: Arc<String>, _value: MokaCacheData, cause: RemovalCause) {
println!("key={key}, cause={cause:?}");
}
fn main() -> anyhow::Result<()> {
let cache = MokaCache::new_default(Some(on_remove), 512);
cache.insert("message", "hello moka", Expiration::Minute(5))?;
let value = cache.get::<_, String>("message");
assert_eq!(value, Some((Expiration::Minute(5), "hello moka".to_string())));
Ok(())
}use moka_cache::{Expiration, MokaCache};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct AppConfig {
path: String,
cache_capacity: u32,
}
fn main() -> anyhow::Result<()> {
let cache = MokaCache::new_default(None, 128);
let config = AppConfig {
path: "./data".to_string(),
cache_capacity: 1024,
};
cache.insert("app-config", config.clone(), Expiration::Never)?;
let value = cache.get::<_, AppConfig>("app-config");
assert_eq!(value, Some((Expiration::Never, config)));
Ok(())
}let cache = MokaCache::new_default(None, 512);- 第一个参数:可选移除回调
- 第二个参数:最大容量
max_capacity
cache.insert("key", 123_i32, Expiration::Second(30))?;let value = cache.get::<_, i32>("key");返回值类型:
Option<(Expiration, V)>其中:
Expiration是写入时设置的过期策略V是反序列化后的实际值
cache.remove("key");let exists = cache.contains_key("key");let exp = cache.get_exp("key");refresh 会按原来的过期策略重新写入当前 key,从而延长生命周期:
cache.refresh("key")?;如果 key 不存在,会返回错误;如果过期策略是 Expiration::Never,则不会执行刷新。
当前库基于 moka::sync::Cache,并暴露了:
cache.check_exp_interval();这个方法内部会调用 run_pending_tasks(),适合在后台线程中定期执行,以便更及时地触发过期清理和回调。例如:
use std::{thread, time::Duration};
thread::spawn({
let cache = cache_handler.clone();
move || loop {
thread::sleep(Duration::from_millis(50));
cache.check_exp_interval();
}
});如果你的业务依赖“过期后尽快触发移除回调”,建议显式调度这个方法。
只要类型实现了以下 trait,就可以直接缓存:
serde::Serializeserde::de::DeserializeOwned
例如:
Stringbooli32/u32/u64Vec<u8>- 自定义结构体
项目当前暴露的核心类型包括:
MokaCacheMokaCacheHandler = Arc<MokaCache>MokaCacheData = (Expiration, Vec<u8>)Expiration
- key 类型统一使用字符串语义,接口接收
AsRef<str> - value 会以
bincode二进制格式写入缓存 - 读取时如果反序列化失败,会记录错误日志并返回
None refresh的实现是“读取旧值后重新插入”,适合 TTL 续期场景
MIT