Stream: git-wasmtime

Topic: wasmtime / issue #11170 Single-threaded async runtime


view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 13:09):

HoKim98 opened issue #11170:

Thanks for filing a feature request! Please fill out the TODOs below.

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create a buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 13:09):

HoKim98 edited issue #11170:

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create a buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 13:12):

HoKim98 edited issue #11170:

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create a buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

The estimated number of lines: 100~300

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 13:12):

HoKim98 edited issue #11170:

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create a buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

The estimated number of new lines: 100~300

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 13:12):

HoKim98 edited issue #11170:

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create a buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

The estimated number of new lines: 100~500

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 13:13):

HoKim98 edited issue #11170:

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create a buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 13:14):

HoKim98 edited issue #11170:

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 01 2025 at 16:51):

pchickey commented on issue #11170:

Sorry - we have had this discussion in the past, and concluded that, with the current features available in the Rust type system, wasmtime's Send bounds are unfortunately infectious and will be used throughout the public API.

After maintaining wasmtime in tokio embeddings for many years, I'm now maintaining a single-threaded web server embedding for wasmtime where Send is a burden. Unfortunately I have solved this by adding a lot of blatantly false unsafe impl Send for <my types> {} throughout my codebase. But, we've balanced that against all of the known approaches to manage Send's infectiousness in wasmtime, and decided that its the best of the difficult options.

I won't rule out changing the design of wasmtime completely, but its a big project that requires a lot of time and attention from a skilled contributor, and will require a working prototype and RFC in order to land. If you are up for that project, lets talk about it more, but if not, we'll have to suffer together with the way it is now.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 04 2025 at 04:25):

HoKim98 commented on issue #11170:

In my case, specifically when using the wasm32-wasip2 target (i.e., the version that doesn't explicitly depend on the tokio runtime), I haven't actually run into the issue you described.

In particular, I found that the core on_fiber method has evolved over the past year to the point where it has no real dependency on Send. That said, in environments like the tokio runtime where async tasks may be executed across threads, the "infectious" nature of Send often forces us to inject an otherwise void dependency.

To address this, I implemented buddy methods like the one that work correctly even in !Send environments. It's less of a new invention and more of a clone of the existing code adapted for !Send.

Finally, for types like trait Stream, the Send constraint isn't tied to the struct itself but to its implementation, which makes workarounds like unsafe impl Send for <my types> fundamentally impossible. While this is arguably a positive side effect of Send’s strictness, it also means we can’t bypass it even when we're sure the code will never leave the current thread.

Just to share a personal thought: I believe the implementation is fairly straightforward and easy to follow. A prototype is available at the link above, and buddy versions of the multi-stage test code are also planned. I’d love your take on whether you think this should go through an RFC, or if it’s fine to submit as a plain PR.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 07 2025 at 16:42):

alexcrichton commented on issue #11170:

Personally I feel that duplicating Wasmtime's API surface area needs to be very well motivated and ideally is something we can avoid. To that end I'd agree with @pchickey that, while not great, unsafe impl Send is hopefully the way to go. To that ened @HoKim98 I'd like to dig in to why this workaround does not work. Can you share example code?

I agree that your patch is relatively small and looks easy to apply. Where I would disagree I think is how that would be maintained over time:

These are not necessarily showstoppers but to me this is a high bar to clear, possibly higher than you're anticipating. Maintenance over time is an important factor to deciding on API surface area and that's one of my chief concerns here.

I found that the core on_fiber method has evolved over the past year to the point where it has no real dependency on Send

There is a long comment here about this. Yes Send can be removed, no it is not sound to remove it.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 15 2025 at 03:31):

HoKim98 commented on issue #11170:

Hello @alexcrichton , thanks for sharing a great inspection.

I have actively reviewed your suggestion. I completely agree that each of the three milestones you suggested is a big deal and difficult to maintain.

Can you share example code?

I create a sample project that I suffer from: https://github.com/HoKim98/my-actix-wasm-project

If this problem could be solved simply, at least for me, I would no longer need this issue.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 15 2025 at 03:31):

HoKim98 edited a comment on issue #11170:

Hello @alexcrichton , thanks for sharing a great inspection.

I have actively reviewed your suggestion. I completely agree that each of the three milestones you suggested is a big deal and difficult to maintain.

Can you share example code?

I created a sample project that I suffer from: https://github.com/HoKim98/my-actix-wasm-project

If this problem could be solved simply, at least for me, I would no longer need this issue.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 15 2025 at 15:02):

alexcrichton commented on issue #11170:

For any variables live over that .await point, you'll need to use something like:

struct UnsafeSend<T>(T);
unsafe impl<T> Send for UnsafeSend<T> {}

and wrap live variables in UnsafeSend followed by accessing them through the UnsafeSend afterwards. In theory that should resolve the issue.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2025 at 11:00):

HoKim98 closed issue #11170:

Feature

I want to use wasmtime in actix-web, which uses !Send runtime and resources such as HTTPRequest and web::Payload.

But the current runtime requires functions and states to be Sendable.

I thought it's not mandatory to enforce Send trait.
So I have tested on my local without Send and found no problem.

Benefit

We can use wasmtime in the thread-bounded (single-threaded) async runtimes.

It's essential to use wasmtime within actix ecosystem, which provides the input parameters as !Send.

Implementation

My current(initial) idea is to create buddy methods like below:

/// Original method
pub async fn instantiate_async(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance>
where
    T: Send,
{
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store.on_fiber(|store| self.instantiate_impl(store)).await?
}

/// (New) buddy method
pub async fn instantiate_async_single_rt(
    &self,
    mut store: impl AsContextMut<Data = T>,
) -> Result<Instance> {
    let mut store = store.as_context_mut();
    assert!(
        store.0.async_support(),
        "must use sync instantiation when async support is disabled"
    );
    store
        .on_fiber_single_rt(|store| self.instantiate_impl_single_rt(store))
        .await?
}

Alternatives

My another idea is to use cargo features like async-send.
But I think it may break the ecosystem (side-effect).

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2025 at 11:00):

HoKim98 commented on issue #11170:

Thank you @alexcrichton it helped me a lot!


Last updated: Dec 06 2025 at 07:03 UTC