Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why do HTTP plugins have to be run in a web worker? #103

Closed
anderspitman opened this issue Nov 20, 2024 · 2 comments
Closed

Why do HTTP plugins have to be run in a web worker? #103

anderspitman opened this issue Nov 20, 2024 · 2 comments

Comments

@anderspitman
Copy link

My extism plugin is coming along very nicely. I'm pretty confident at this point that it will be able to do everything I need.

One issue I've run into is that the requirement to use a web worker for HTTP plugins adds quite a bit of complexity. Given that JS is async and should be able to handle everything on a single thread, I'm wondering why this is necessary?

@chrisdickinson
Copy link
Contributor

The asynchronous nature of JS ends up being the issue! At the time of writing, Wasm runs on the same thread that it's invoked on and expects host functions to complete synchronously with respect to that thread. So if you were to call fetch in a (synchronous) host function from Wasm, the host function would return before fetch resolved– you'd need to split the http_request call into two calls, http_request and http_request_poll. (Or have the host function call back into the Wasm later.) This would diverge from Extism host function behavior on all other platforms – and there's no1 way to make a (sync) HTTP call on most JS platforms.

So, what we do is push the guest onto a background Worker thread, which can block until async host functions executed on the main thread are resolved, essentially suspending the execution of the Wasm at the host function call site until the HTTP request resolves.

Luckily, there's an effort to standardize this promising/Suspending behavior in JS, JS Promise Integration, or "JSPI". JSPI is available in Deno 2 and Node v23 using the v8 --experimental-wasm-stack-switching flag– I've been busily adding support for it this week (#100, #102.) It essentially achieves the same goal – suspending the Wasm stack when it reaches an async host function and returning control to the initial Wasm callsite – but it doesn't incur the overhead of spinning up Worker threads.

That said, there are other reasons to execute sync, compute-heavy Wasm on background threads– (as you know!) contention on the main thread can seriously affect the performance of most JS server platforms. So we'll continue to support Worker threads into the future. (But the good news is that JSPI will make supporting the worker threads even simpler, too, in that we won't have to use our own locks for copying data up and down.)

Footnotes

  1. There's one exception – synchronous XMLHttpRequest – but that has been pretty widely deprecated and many platforms don't support it.

@anderspitman
Copy link
Author

Sounds like I'm on the bleeding edge. Thank you for the detailed answer!

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

No branches or pull requests

2 participants