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,41 +173,43 @@ fn DbStatusTab() -> Element {
|
|||||||
load_once();
|
load_once();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 自动刷新:interval 变化时 use_future 重新执行,内部周期 sleep 后重新 load。
|
// 自动刷新:使用官方推荐模式——一个永不重建的长生命周期 loop,在每次循环
|
||||||
// wasm32 才有意义(SSR 不轮询);sleep 用 web_sys 的 setTimeout 包成 JsFuture,
|
// 内部读取 refresh_interval 的当前值,自然响应间隔切换。
|
||||||
// 避免引入新依赖。interval 在 use_future 依赖里读取,变化即重建 future。
|
// 旧做法在闭包同步体内读 status/loading/error signal,导致这些 signal 每次
|
||||||
use_future(move || {
|
// .set() 后都触发 use_future 重建,产生多个并发 loop(请求爆炸)。
|
||||||
// 在依赖闭包里读 interval,使 use_future 在它变化时重新执行。
|
use_future(move || async move {
|
||||||
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")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
let secs = interval_secs.unwrap_or(0);
|
|
||||||
if secs == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loop {
|
loop {
|
||||||
|
// 每次循环读最新 interval(signal 的 Copy 语义,直接调用即可)。
|
||||||
|
let secs = refresh_interval().unwrap_or(0);
|
||||||
|
if secs == 0 {
|
||||||
|
// 手动模式:短暂 yield,让事件循环呼吸,避免忙等;
|
||||||
|
// 用户切换到自动模式后最多等 200ms 即响应。
|
||||||
|
wasm_sleep(200).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
wasm_sleep(secs * 1000).await;
|
wasm_sleep(secs * 1000).await;
|
||||||
loading_f.set(true);
|
// 二次检查:sleep 期间用户可能切回手动。
|
||||||
|
if refresh_interval().is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
loading.set(true);
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
match get_db_status().await {
|
match get_db_status().await {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
status_f.set(Some(s));
|
status.set(Some(s));
|
||||||
error_f.set(None);
|
error.set(None);
|
||||||
}
|
}
|
||||||
Err(e) => error_f.set(Some(e.to_string())),
|
Err(e) => error.set(Some(e.to_string())),
|
||||||
}
|
}
|
||||||
loading_f.set(false);
|
loading.set(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let _ = (interval_secs, status_f, loading_f, error_f);
|
let _ = (status, loading, error, refresh_interval);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -461,38 +463,37 @@ fn ServerStatusTab() -> Element {
|
|||||||
load_once();
|
load_once();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 自动刷新:refresh_ms 变化时重建 future。
|
// 自动刷新:同 DbStatusTab,采用官方推荐的单一长生命周期 loop 模式。
|
||||||
use_future(move || {
|
// 闭包体内不读任何 signal(避免隐式依赖追踪导致重建),loop 内部实时读取。
|
||||||
let interval_ms = refresh_ms();
|
use_future(move || async move {
|
||||||
let mut status_f = status;
|
|
||||||
let mut loading_f = loading;
|
|
||||||
let mut error_f = error;
|
|
||||||
async move {
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
let ms = interval_ms.unwrap_or(0);
|
|
||||||
if ms == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loop {
|
loop {
|
||||||
|
let ms = refresh_ms().unwrap_or(0);
|
||||||
|
if ms == 0 {
|
||||||
|
wasm_sleep(200).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
wasm_sleep(ms).await;
|
wasm_sleep(ms).await;
|
||||||
loading_f.set(true);
|
if refresh_ms().is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
loading.set(true);
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
match get_server_status().await {
|
match get_server_status().await {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
status_f.set(Some(s));
|
status.set(Some(s));
|
||||||
error_f.set(None);
|
error.set(None);
|
||||||
}
|
}
|
||||||
Err(e) => error_f.set(Some(e.to_string())),
|
Err(e) => error.set(Some(e.to_string())),
|
||||||
}
|
}
|
||||||
loading_f.set(false);
|
loading.set(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let _ = (interval_ms, status_f, loading_f, error_f);
|
let _ = (status, loading, error, refresh_ms);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user