fix and test spawn_forever (#2216)
This commit is contained in:
1 parent
947b23bda5
commit
5df333fca2
3 files changed
+44
-9
No files matched your search
@@ -93,8 +93,10 @@ pub fn spawn(fut: impl Future<Output = ()> + 'static) -> Task {
|
|||||||
/// Spawn a future that Dioxus won't clean up when this component is unmounted
|
/// Spawn a future that Dioxus won't clean up when this component is unmounted
|
||||||
///
|
///
|
||||||
/// This is good for tasks that need to be run after the component has been dropped.
|
/// This is good for tasks that need to be run after the component has been dropped.
|
||||||
|
///
|
||||||
|
/// **This will run the task in the root scope. Any calls to global methods inside the future (including `context`) will be run in the root scope.**
|
||||||
pub fn spawn_forever(fut: impl Future<Output = ()> + 'static) -> Option<Task> {
|
pub fn spawn_forever(fut: impl Future<Output = ()> + 'static) -> Option<Task> {
|
||||||
Runtime::with_current_scope(|cx| cx.spawn_forever(fut))
|
Runtime::with_scope(ScopeId::ROOT, |cx| cx.spawn(fut))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Informs the scheduler that this task is no longer needed and should be removed.
|
/// Informs the scheduler that this task is no longer needed and should be removed.
|
||||||
|
|||||||
@@ -265,14 +265,6 @@ impl Scope {
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawn a future that Dioxus won't clean up when this component is unmounted
|
|
||||||
///
|
|
||||||
/// This is good for tasks that need to be run after the component has been dropped.
|
|
||||||
pub fn spawn_forever(&self, fut: impl Future<Output = ()> + 'static) -> Task {
|
|
||||||
// The root scope will never be unmounted so we can just add the task at the top of the app
|
|
||||||
Runtime::with(|rt| rt.spawn(self.id, fut)).expect("Runtime to exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mark this component as suspended on a specific task and then return None
|
/// Mark this component as suspended on a specific task and then return None
|
||||||
pub fn suspend(&self, task: Task) -> Option<Element> {
|
pub fn suspend(&self, task: Task) -> Option<Element> {
|
||||||
self.last_suspendable_task.set(Some(task));
|
self.last_suspendable_task.set(Some(task));
|
||||||
|
|||||||
@@ -49,6 +49,47 @@ async fn running_async() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn spawn_forever_persists() {
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
static POLL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
fn app() -> Element {
|
||||||
|
if generation() > 0 {
|
||||||
|
rsx!(div {})
|
||||||
|
} else {
|
||||||
|
needs_update();
|
||||||
|
rsx!(Child {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn Child() -> Element {
|
||||||
|
spawn_forever(async move {
|
||||||
|
loop {
|
||||||
|
POLL_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||||
|
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rsx!(div {})
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dom = VirtualDom::new(app);
|
||||||
|
|
||||||
|
dom.rebuild(&mut dioxus_core::NoOpMutations);
|
||||||
|
dom.render_immediate(&mut dioxus_core::NoOpMutations);
|
||||||
|
|
||||||
|
tokio::select! {
|
||||||
|
_ = dom.wait_for_work() => {}
|
||||||
|
_ = tokio::time::sleep(Duration::from_millis(500)) => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// By the time the tasks are finished, we should've accumulated ticks from two tasks
|
||||||
|
// Be warned that by setting the delay to too short, tokio might not schedule in the tasks
|
||||||
|
assert_eq!(POLL_COUNT.load(Ordering::Relaxed), 10);
|
||||||
|
}
|
||||||
|
|
||||||
/// Prove that yield_now doesn't cause a deadlock
|
/// Prove that yield_now doesn't cause a deadlock
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn yield_now_works() {
|
async fn yield_now_works() {
|
||||||
|
|||||||
Reference in new issue
Block a user