Skip to main content

tdm_server_rust/cache/
auth_snapshot_cache.rs

1//! 鉴权用组员快照短 TTL 缓存
2//!
3//! 每次请求鉴权时查询组员信息的频率极高,
4//! 使用 moka 异步缓存减少数据库查询。
5//! TTL 默认 30 秒,可通过 `AUTH_SNAPSHOT_CACHE_SECS` 环境变量调整。
6//!
7//! ## 缓存策略
8//!
9//! - **Key**: 组员 ID (`i32`)
10//! - **Value**: `Arc<Member>`(组员快照 + 岗位 ID 列表)
11//! - **TTL**: 30 秒(默认),组员信息变更较少但需要及时反映权限变化
12//! - **失效**: 组员更新/删除时调用 [`invalidate_auth_snapshot`] 主动失效
13
14use crate::{
15    app::AppState,
16    entity::member::Member,
17    error::AppError,
18    repository::member_repo::MemberRepository,
19};
20use std::sync::Arc;
21use std::time::Duration;
22
23/// 鉴权快照缓存类型
24///
25/// 键为组员 ID,值为组员快照(含岗位列表)。
26/// moka 的 `time_to_live` 确保过期后自动重新查询数据库。
27pub type AuthSnapshotCache = moka::future::Cache<i32, Arc<Member>>;
28
29/// 创建鉴权快照缓存实例
30///
31/// TTL 由环境变量 `AUTH_SNAPSHOT_CACHE_SECS` 控制,默认 30 秒。
32pub fn new_auth_snapshot_cache() -> AuthSnapshotCache {
33    let ttl_secs = std::env::var("AUTH_SNAPSHOT_CACHE_SECS")
34        .ok()
35        .and_then(|v| v.parse().ok())
36        .unwrap_or(30);
37    moka::future::Cache::builder()
38        .time_to_live(Duration::from_secs(ttl_secs))
39        .build()
40}
41
42/// 获取鉴权快照
43///
44/// 先从缓存查询,未命中时查数据库并回填缓存。
45///
46/// # 参数
47///
48/// - `state`: 应用状态(持有缓存实例和数据库连接池)
49/// - `member_id`: 组员 ID
50///
51/// # 返回值
52///
53/// 返回组员快照(含岗位 ID 列表)。
54///
55/// # Errors
56///
57/// - `AppError::business("组员不存在喵")` — ID 不存在
58/// - `AppError::Database` — 查询失败
59pub async fn get_auth_snapshot_cached(
60    state: &AppState,
61    member_id: i32,
62) -> Result<Member, AppError> {
63    if let Some(cached) = state.auth_snapshot_cache.get(&member_id).await {
64        return Ok((*cached).clone());
65    }
66    let repo = MemberRepository::new(state.db.clone());
67    let member = repo.get_auth_snapshot(member_id).await?;
68    state
69        .auth_snapshot_cache
70        .insert(member_id, Arc::new(member.clone()))
71        .await;
72    Ok(member)
73}
74
75/// 使指定组员的鉴权快照缓存失效
76///
77/// 组员信息(权限、岗位)变更后调用,确保下次请求获取最新数据。
78pub async fn invalidate_auth_snapshot(state: &AppState, member_id: i32) {
79    state.auth_snapshot_cache.invalidate(&member_id).await;
80}
81
82/// 使全部鉴权快照缓存失效
83///
84/// 批量操作后调用(如批量更新岗位),避免逐条失效。
85pub async fn invalidate_all_auth_snapshots(state: &AppState) {
86    state.auth_snapshot_cache.invalidate_all();
87}