Update command trigger to WASI P3#87
Conversation
dicej
left a comment
There was a problem hiding this comment.
Error: component imports instance
wasi:http/types@0.3.0-rc-2026-03-15, but a matching implementation was not found in the linkerCaused by:
0: instance exportfieldshas the wrong type
1: resource implementation is missing
This indicates that neither wasmtime_wasi_http::p3::add_to_linker nor any of the more specific add_to_linker functions provided by that crate have been called for the component's linker. Normally, that's spin_factor_outbound_http's job.
I always get lost in the layers of dependency injection in Spin factors, so I don't know offhand why the outbound HTTP factor might not have been injected here, nor why it was injected fine in the p2-based version of this trigger, but that's my guess as to what's happening.
| let res: Response = send(req).await.unwrap(); | ||
| println!("Your IP is: {}", String::from_utf8_lossy(res.body())); | ||
| }); | ||
| #[tokio::main(flavor = "current_thread")] |
There was a problem hiding this comment.
I'm surprised to see this here; neither Tokio nor the Rust compiler support WASIp3 yet, and thus they don't know how transform an async fn main declaration into the wasi:cli/run#run export that WASIp3 requires.
The only way I'm aware of currently to export wasi:cli/run#run is to use the wit-bindgen-generated bindings directly (or write the bindings by hand, if you're feeling ambitious).
There was a problem hiding this comment.
Hah, then presumably it doesn't work and it's just being disguised by the HTTP import failure happening first!
If there's no idiomatic way to write an async main, is there a way to call async APIs from sync main? I don't think WIT spawn works, and the usual Tokio block-on methods will presumably rely on the Tokio scheduler...?
ETA: no, because sync main becomes a sync export, and calling async APIs from a sync entry point is FORBIDDEN
so... should we hold off on moving Command to async?
There was a problem hiding this comment.
We could implement our own e.g. #[spin::main] macro which transforms async main(){...} into an export of wasi:cli/run, analogous to what we do for HTTP. Or embrace the non-idiomatic-but-servicable approach of using the wit-bindgen-generated bindings directly for the export (and still use the sdk for the imports). Or hold off updating this trigger. All sound reasonable to me.
There was a problem hiding this comment.
I'd be fine to just implement wasi:cli/command directly. E.g.
// lib.rs
use spin_sdk::{wasip3, http::{EmptyBody, body::IncomingBodyExt, Request, send}};
wasip3::cli::command::export!(Job);
struct Job;
impl wasip3::exports::cli::run::Guest for Job {
async fn run() -> Result<(), ()> {
match do_job().await {
Ok(()) => Ok(()),
Err(e) => {
eprintln!("{e}");
Err(())
}
}
}
}
async fn do_job() -> anyhow::Result<()> {
let request = Request::get("https://myip.fermyon.app").body(EmptyBody::new())?;
let response = send(request).await?;
let response_bytes = response.into_body().bytes().await?;
let response_text = String::from_utf8_lossy(&response_bytes.as_ref());
println!("Your IP is: {}", response_text);
Ok(())
}There was a problem hiding this comment.
This would require changing main.rs -> lib.rs and adding [lib] crate-type = ["cdylib"] to Cargo.toml.
There was a problem hiding this comment.
That would make me sad, because we lose the idiomatic fn main() of Rust commands. I accept that "it works" is more important than "Ivan is sad" though!
There was a problem hiding this comment.
I think it's the best we can do until presumably wasi p3 is wired up to std? a la a wasm32-wasip3 target,
There was a problem hiding this comment.
Updated! Thanks @dicej and @fibonacci1729!
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
fibonacci1729
left a comment
There was a problem hiding this comment.
Looks good. Can you check the READMEs to ensure theyre up to date?
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
|
Ugh sorry |
|
Okay I think for this one we need it (at least for now) to support both P2 and P3, because the way I have done it, Rust commands ( |
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
Once again I'm afraid I need to rope in the WASI experts...
The
helloCLI sample works fine, but I am having trouble with theasyncone, which does some outbound HTTP. I have this compiling, but when I run it, it fails with:The host is linking to Spin main (for the WASI implementation), and the guest is linking to Rust SDK main (for the HTTP client implementation). We have these working together elsewhere, so I am not sure why they are mismatching here. Is it because I'm using
wasmtime_wasi::p3::bindings::Command::newto access the instance entry point, and that has its own copy of the HTTP bindings or something? That doesn't feel right...So... sorry to do this to you again, but could you point me at what I have wrong please? Thanks!