Skip to content

guest-rust: Implement a Task handle for spawned futures - #1710

Open
adamrk wants to merge 1 commit into
bytecodealliance:mainfrom
adamrk:abk/task-handle
Open

guest-rust: Implement a Task handle for spawned futures#1710
adamrk wants to merge 1 commit into
bytecodealliance:mainfrom
adamrk:abk/task-handle

Conversation

@adamrk

@adamrk adamrk commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

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.

Note: The naming and cancellation behavior here matches async_task::Task because that's what we were already using in wstd and it would allow switching to wit_bindgen::Task without requiring a wrapper. But I could also see an argument for going with the naming and behavior of tokio, so happy to switch to that if other people think it's better.

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();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants