fix(admin): 修复服务器/数据库状态自动刷新失效 Bug
use_future 旧实现在同步闭包体内捕获 status/loading/error signal,
导致这些 signal 每次 .set() 后都触发 use_future 重建新 loop,
旧 loop 同时继续运行,造成并发 loop 指数增长(请求爆炸),
实际效果等同于自动刷新完全失效或行为异常。
修复:采用 Dioxus 0.7 官方推荐模式——
- use_future 闭包直接返回 async move {},不在同步层读任何 signal
- loop 内每次迭代读 refresh_interval/refresh_ms 的实时值
- 手动模式(interval = 0)改为 200ms yield + continue,
使切换到自动模式时最多延迟 200ms 生效,避免忙等
- sleep 结束后二次检查 interval,防止 sleep 期间用户切回手动时
仍然发起一次无意义请求
同时修复 DbStatusTab 和 ServerStatusTab 两处。
This commit is contained in:
parent
404f85b732
commit
9cf0e605d4
@ -173,42 +173,44 @@ fn DbStatusTab() -> Element {
|
||||
load_once();
|
||||
});
|
||||
|
||||
// 自动刷新:interval 变化时 use_future 重新执行,内部周期 sleep 后重新 load。
|
||||
// wasm32 才有意义(SSR 不轮询);sleep 用 web_sys 的 setTimeout 包成 JsFuture,
|
||||
// 避免引入新依赖。interval 在 use_future 依赖里读取,变化即重建 future。
|
||||
use_future(move || {
|
||||
// 在依赖闭包里读 interval,使 use_future 在它变化时重新执行。
|
||||
let interval_secs = refresh_interval();
|
||||
let mut status_f = status;
|
||||
let mut loading_f = loading;
|
||||
let mut error_f = error;
|
||||
async move {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
let secs = interval_secs.unwrap_or(0);
|
||||
// 自动刷新:使用官方推荐模式——一个永不重建的长生命周期 loop,在每次循环
|
||||
// 内部读取 refresh_interval 的当前值,自然响应间隔切换。
|
||||
// 旧做法在闭包同步体内读 status/loading/error signal,导致这些 signal 每次
|
||||
// .set() 后都触发 use_future 重建,产生多个并发 loop(请求爆炸)。
|
||||
use_future(move || async move {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
loop {
|
||||
// 每次循环读最新 interval(signal 的 Copy 语义,直接调用即可)。
|
||||
let secs = refresh_interval().unwrap_or(0);
|
||||
if secs == 0 {
|
||||
return;
|
||||
// 手动模式:短暂 yield,让事件循环呼吸,避免忙等;
|
||||
// 用户切换到自动模式后最多等 200ms 即响应。
|
||||
wasm_sleep(200).await;
|
||||
continue;
|
||||
}
|
||||
loop {
|
||||
wasm_sleep(secs * 1000).await;
|
||||
loading_f.set(true);
|
||||
spawn(async move {
|
||||
match get_db_status().await {
|
||||
Ok(s) => {
|
||||
status_f.set(Some(s));
|
||||
error_f.set(None);
|
||||
}
|
||||
Err(e) => error_f.set(Some(e.to_string())),
|
||||
wasm_sleep(secs * 1000).await;
|
||||
// 二次检查:sleep 期间用户可能切回手动。
|
||||
if refresh_interval().is_none() {
|
||||
continue;
|
||||
}
|
||||
loading.set(true);
|
||||
spawn(async move {
|
||||
match get_db_status().await {
|
||||
Ok(s) => {
|
||||
status.set(Some(s));
|
||||
error.set(None);
|
||||
}
|
||||
loading_f.set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let _ = (interval_secs, status_f, loading_f, error_f);
|
||||
Err(e) => error.set(Some(e.to_string())),
|
||||
}
|
||||
loading.set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let _ = (status, loading, error, refresh_interval);
|
||||
}
|
||||
});
|
||||
|
||||
// Option<DbStatus> 非 Copy,读出来克隆一份供 rsx 消费。
|
||||
@ -461,39 +463,38 @@ fn ServerStatusTab() -> Element {
|
||||
load_once();
|
||||
});
|
||||
|
||||
// 自动刷新:refresh_ms 变化时重建 future。
|
||||
use_future(move || {
|
||||
let interval_ms = refresh_ms();
|
||||
let mut status_f = status;
|
||||
let mut loading_f = loading;
|
||||
let mut error_f = error;
|
||||
async move {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
let ms = interval_ms.unwrap_or(0);
|
||||
// 自动刷新:同 DbStatusTab,采用官方推荐的单一长生命周期 loop 模式。
|
||||
// 闭包体内不读任何 signal(避免隐式依赖追踪导致重建),loop 内部实时读取。
|
||||
use_future(move || async move {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
loop {
|
||||
let ms = refresh_ms().unwrap_or(0);
|
||||
if ms == 0 {
|
||||
return;
|
||||
wasm_sleep(200).await;
|
||||
continue;
|
||||
}
|
||||
loop {
|
||||
wasm_sleep(ms).await;
|
||||
loading_f.set(true);
|
||||
spawn(async move {
|
||||
match get_server_status().await {
|
||||
Ok(s) => {
|
||||
status_f.set(Some(s));
|
||||
error_f.set(None);
|
||||
}
|
||||
Err(e) => error_f.set(Some(e.to_string())),
|
||||
wasm_sleep(ms).await;
|
||||
if refresh_ms().is_none() {
|
||||
continue;
|
||||
}
|
||||
loading.set(true);
|
||||
spawn(async move {
|
||||
match get_server_status().await {
|
||||
Ok(s) => {
|
||||
status.set(Some(s));
|
||||
error.set(None);
|
||||
}
|
||||
loading_f.set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let _ = (interval_ms, status_f, loading_f, error_f);
|
||||
Err(e) => error.set(Some(e.to_string())),
|
||||
}
|
||||
loading.set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let _ = (status, loading, error, refresh_ms);
|
||||
}
|
||||
});
|
||||
|
||||
let current = status.read().clone();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user