commit 7c1060cbb8ac5004cf85fb9a33649e5f5816560c
parent e257818f68174fb537741369704be17243790e4e
Author: triesap <triesap@radroots.dev>
Date: Tue, 20 Jan 2026 16:22:20 +0000
app: abort logs auto-refresh on unmount
- replace interval forget with abortable refresh task
- add futures dependency for abort handle wiring
- register on_cleanup to stop the refresh loop
- keep refresh cadence and manual button behavior
Diffstat:
3 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -748,6 +748,8 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
dependencies = [
+ "futures-channel",
+ "futures-core",
"js-sys",
"wasm-bindgen",
]
diff --git a/app/Cargo.toml b/app/Cargo.toml
@@ -14,9 +14,10 @@ leptos = { workspace = true, features = ["csr"] }
leptos_router = { workspace = true }
wasm-bindgen.workspace = true
wasm-bindgen-futures.workspace = true
+futures.workspace = true
js-sys.workspace = true
web-sys.workspace = true
-gloo-timers.workspace = true
+gloo-timers = { workspace = true, features = ["futures"] }
radroots-app-core = { path = "../crates/core" }
radroots-log = { path = "../refs/crates/log", default-features = false }
tracing-wasm = "0.2"
@@ -26,7 +27,6 @@ serde_json.workspace = true
uuid.workspace = true
[dev-dependencies]
-futures.workspace = true
async-trait.workspace = true
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
diff --git a/app/src/logs.rs b/app/src/logs.rs
@@ -1,6 +1,8 @@
#![forbid(unsafe_code)]
-use gloo_timers::callback::Interval;
+use futures::future::{AbortHandle, Abortable};
+use futures::StreamExt;
+use gloo_timers::future::IntervalStream;
use leptos::prelude::*;
use leptos::task::spawn_local;
use std::rc::Rc;
@@ -120,8 +122,18 @@ pub fn LogsPage() -> impl IntoView {
}
interval_started.set(true);
let refresh = Rc::clone(&interval_effect);
- let interval = Interval::new(logs_auto_refresh_ms(), move || refresh());
- interval.forget();
+ let (abort_handle, abort_reg) = AbortHandle::new_pair();
+ let abort_handle_cleanup = abort_handle.clone();
+ spawn_local(async move {
+ let mut ticks = IntervalStream::new(logs_auto_refresh_ms());
+ let task = async move {
+ while ticks.next().await.is_some() {
+ refresh();
+ }
+ };
+ let _ = Abortable::new(task, abort_reg).await;
+ });
+ on_cleanup(move || abort_handle_cleanup.abort());
});
let status_label = move || if loading.get() { "loading" } else { "idle" };
view! {