yggdrasil/src/ssr_cache.rs
xfy 373498870a
Some checks failed
CI / check (push) Failing after 5m35s
CI / build (push) Has been skipped
style: apply cargo fmt to workspace
2026-06-29 13:47:40 +08:00

73 lines
2.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! SSR 增量渲染缓存失效的未来就绪基础设施。
//!
//! 本模块维护一个全局单调递增的世代号generation。文章写入成功后调用方会
//! 使其递增,从而**标记** SSR 渲染结果已过期。然而:
//!
//! **Dioxus 0.7 的增量渲染器使用请求 URI 的 `path_and_query()` 作为内部缓存键,
//! 且没有暴露公开 API 供外部代码自定义缓存键或按路由失效已渲染页面。**
//! 因此,当前世代号并**不会**实际使 Dioxus 的 SSR 缓存失效;它只是为未来 API
//! 准备好状态,并在请求/响应中提供可观测性。
//!
//! 在 Dioxus 提供以下任一能力之前,有效的 SSR 缓存失效手段仍是调低
//! `SSR_CACHE_SECS` 这一兜底 TTL
//! - 自定义增量渲染缓存键的回调;或
//! - 从 server function 内部按路由失效缓存的公开 API。
//!
//! 当前实现:
//! - `bump_global_generation()` / `current_global_generation()`:全局世代号。
//! - `SsrGeneration`:注入到请求扩展中的类型;未来 Dioxus 支持读取扩展生成
//! 缓存键时可直接使用。
//! - `src/main.rs` 的中间件把当前世代号附加到 `X-SSR-Generation` 响应头
//! (仅 GET 请求),便于调试与监控。
//!
//! 仅在启用 `server` feature 时编译。
#![cfg(feature = "server")]
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::LazyLock;
/// 全局 SSR 世代号。
///
/// 任何文章写入操作都会使其递增,从而让所有基于该全局世代的 SSR 缓存键在未来
/// Dioxus 支持自定义缓存键时失效。
static GLOBAL_GENERATION: LazyLock<AtomicU64> = LazyLock::new(AtomicU64::default);
/// 注入到请求扩展中的当前 SSR 世代号。
///
/// 这是为未来 Dioxus 支持自定义 SSR 缓存键预留的钩子。当前 Dioxus 0.7 的渲染器
/// 不会读取此扩展。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SsrGeneration(pub u64);
/// 原子递增并返回新的全局世代号。
pub fn bump_global_generation() -> u64 {
GLOBAL_GENERATION
.fetch_add(1, Ordering::SeqCst)
.wrapping_add(1)
}
/// 返回当前全局世代号。
pub fn current_global_generation() -> u64 {
GLOBAL_GENERATION.load(Ordering::SeqCst)
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
#[test]
#[serial]
fn global_generation_is_monotonic() {
let before = current_global_generation();
let g1 = bump_global_generation();
let g2 = bump_global_generation();
let current = current_global_generation();
assert!(g1 > before || g1 == 1);
assert!(g2 > g1);
assert_eq!(current, g2);
}
}