guest-rust: Implement a Task handle for spawned futures - #1710
Conversation
The `Task` can be awaited to get the returned value of the future, or it can be dropped or explicitly canceled to cancel the future. It can also be detached to allow running in the background and match the previous behavior of `spawn_local`. It's possible that the component-model task into which the future was spawned could be canceled while the `Task` referencing it is still alive. In that case, awaiting or canceling the task will return `None`.
| unsafe { SPAWNED.push(Box::pin(future)) } | ||
| pub fn spawn_local<T: 'static>(future: impl Future<Output = T> + 'static) -> Task<T> { | ||
| let (sender, receiver) = oneshot::channel(); | ||
| let (abort, registration) = AbortHandle::new_pair(); |
There was a problem hiding this comment.
Instead of AbortHandle which I believe is a separate allocation from the oneshot, could the oneshot's close and poll_cancelled methods be used instead?
| Task { | ||
| receiver, | ||
| abort, | ||
| cancel_on_drop: true, |
There was a problem hiding this comment.
Semantically I think this should preserve the preexisting behavior where if Task<T> isn't interacted with then it's not cancelled. That matches the semantics of std::thread and tokio::task IIRC
| /// | ||
| /// This returns the task's output if it completed before it could be | ||
| /// cancelled, or `None` if it was cancelled or otherwise terminated. | ||
| pub async fn cancel(mut self) -> Option<T> { |
There was a problem hiding this comment.
I might recommend drawing inspiration from Tokio's JoinHandle for this method signature, notably changing this to fn cancel(&self) (or maybe &mut self). That way this can be decoupled with the Future for Task<T> implementation below as well. (e.g. the protocol is cancel-then-await if users care about the race)
The
Taskcan be awaited to get the returned value of the future, or it can be dropped or explicitly canceled to cancel the future. It can also be detached to allow running in the background and match the previous behavior ofspawn_local.It's possible that the component-model task into which the future was spawned could be canceled while the
Taskreferencing it is still alive. In that case, awaiting or canceling the task will returnNone.Note: The naming and cancellation behavior here matches
async_task::Taskbecause that's what we were already using inwstdand it would allow switching towit_bindgen::Taskwithout requiring a wrapper. But I could also see an argument for going with the naming and behavior oftokio, so happy to switch to that if other people think it's better.