Skip to content

Track whether there are any async tasks in a store#13246

Merged
alexcrichton merged 2 commits intobytecodealliance:mainfrom
alexcrichton:poll-tasks-in-a-store
May 1, 2026
Merged

Track whether there are any async tasks in a store#13246
alexcrichton merged 2 commits intobytecodealliance:mainfrom
alexcrichton:poll-tasks-in-a-store

Conversation

@alexcrichton
Copy link
Copy Markdown
Member

This commit adds a new API to Accessor to learn whether there are any async tasks that are "interesting" in a store. This is borne out of many discussions over the past few weeks amongst a number of folks where the basic problem is that for WASIp3 HTTP guests there's no way right now to send a signal of "keep me alive after I send my response" because that's post-return-style work. In WASIp2 this was modeled where the outparam that was passed in was set, and then work was done before returning. With WASIp3, however, a response is sent by returning which means that this is no longer possible.

The general idea is that Wasmtime will now consider all tasks which have not yet exited as "interesting". These tasks in theory mean that the store should be kept alive as the guest still has work to complete. Note that tasks first return, and then exit, and they're still considered interesting after returning before they exit. In the future it's expected that the component model might have an ABI option to say "this task, by default, isn't interesting" with an opt-in method at runtime of saying "ok wait but yes this is interesting". In this manner it's expected that not all tasks for all of time will be considered interesting, only those that are intentionally opted-in to being interesting (and today that just so happens to be all of them).

The API itself on Accessor is a poll_*-style function which enables both checking to see if there are no more tasks remaining as well as registering a callback to get notified when there are actually no more tasks remaining. In this manner HTTP servers can await this as one of the events that concludes when a guest is finished processing.

The implementation of this API required some refactoring of concurrent.rs. Namely I wanted to have a relatively "narrow waist" through which increments/decrements of this internal counter happened to ensure that nothing was forgot. This is a bit non-trivial because there are a number of situations which means that a task is "exited", such as:

  • A synchronously lifted function returns.
  • An asynchronously lifted function returns CALLBACK_CODE_EXIT.
  • An asynchronously lifted function is stuck in the STARTING state, and then gets cancelled.
  • A task is running, is then cancelled, acknowledges the cancellation, and then exits.
  • A task with threads exits without actually returning, and then one of its threads returns for it.

For now the logic of "are interesting tasks done" is now hooked into cleanup_thread. This will likely require adjusting in the future for threads because in this last bullet the task.return invocation is the point where all conditions are met (main thread exited, task returned) as opposed to when the thread itself exits. For now though this is intended to be as close an approximation as possible.

Throughout this implementation I've performed a number of refactorings to reduce duplication, shuffle where methods are implemented, reduce some verbosity, etc. There are debug assertions in place for if this predicate ever goes wrong, which is intended to assist during development.

@alexcrichton alexcrichton requested a review from dicej April 30, 2026 22:56
@alexcrichton alexcrichton requested review from a team as code owners April 30, 2026 22:56
@github-actions github-actions Bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label May 1, 2026
Comment thread crates/wasi-http/src/handler.rs Outdated
Comment thread crates/wasi-http/src/handler.rs
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs Outdated
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs
Comment thread crates/wasmtime/src/runtime/component/concurrent.rs Outdated
This commit adds a new API to `Accessor` to learn whether there are any
async tasks that are "interesting" in a store. This is borne out of many
discussions over the past few weeks amongst a number of folks where the
basic problem is that for WASIp3 HTTP guests there's no way right now to
send a signal of "keep me alive after I send my response" because that's
post-return-style work. In WASIp2 this was modeled where the outparam
that was passed in was set, and then work was done before returning.
With WASIp3, however, a response is sent by returning which means that
this is no longer possible.

The general idea is that Wasmtime will now consider all tasks which have
not yet exited as "interesting". These tasks in theory mean that the
store should be kept alive as the guest still has work to complete. Note
that tasks first return, and then exit, and they're still considered
interesting after returning before they exit. In the future it's
expected that the component model might have an ABI option to say "this
task, by default, isn't interesting" with an opt-in method at runtime of
saying "ok wait but yes this is interesting". In this manner it's
expected that not all tasks for all of time will be considered
interesting, only those that are intentionally opted-in to being
interesting (and today that just so happens to be all of them).

The API itself on `Accessor` is a `poll_*`-style function which enables
both checking to see if there are no more tasks remaining as well as
registering a callback to get notified when there are actually no more
tasks remaining. In this manner HTTP servers can await this as one of
the events that concludes when a guest is finished processing.

The implementation of this API required some refactoring of
`concurrent.rs`. Namely I wanted to have a relatively "narrow waist"
through which increments/decrements of this internal counter happened to
ensure that nothing was forgot. This is a bit non-trivial because there
are a number of situations which means that a task is "exited", such as:

* A synchronously lifted function returns.
* An asynchronously lifted function returns `CALLBACK_CODE_EXIT`.
* An asynchronously lifted function is stuck in the `STARTING` state,
  and then gets cancelled.
* A task is running, is then cancelled, acknowledges the cancellation,
  and then exits.
* A task with threads exits without actually returning, and then one of
  its threads returns for it.

For now the logic of "are interesting tasks done" is now hooked into
`cleanup_thread`. This will likely require adjusting in the future for
threads because in this last bullet the `task.return` invocation is the
point where all conditions are met (main thread exited, task returned)
as opposed to when the thread itself exits. For now though this is
intended to be as close an approximation as possible.

Throughout this implementation I've performed a number of refactorings
to reduce duplication, shuffle where methods are implemented, reduce
some verbosity, etc. There are debug assertions in place for if this
predicate ever goes wrong, which is intended to assist during
development.
@alexcrichton alexcrichton force-pushed the poll-tasks-in-a-store branch from 9b895de to ac2c3e0 Compare May 1, 2026 17:42
@alexcrichton alexcrichton enabled auto-merge May 1, 2026 17:46
Now that their lifetime is extended they need to be included in this
calculation.
@alexcrichton alexcrichton added this pull request to the merge queue May 1, 2026
Merged via the queue into bytecodealliance:main with commit 9adb0f9 May 1, 2026
48 checks passed
@alexcrichton alexcrichton deleted the poll-tasks-in-a-store branch May 1, 2026 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasmtime:api Related to the API of the `wasmtime` crate itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants