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

wasm32-wasi stability/production-readiness (tests) #351

Open
lastmjs opened this issue Aug 6, 2024 · 13 comments
Open

wasm32-wasi stability/production-readiness (tests) #351

lastmjs opened this issue Aug 6, 2024 · 13 comments

Comments

@lastmjs
Copy link

lastmjs commented Aug 6, 2024

Hi,

I'm highly considering integrating rquickjs into our project. We need a stable/production-ready QuickJS bindings in Rust for the wasm32-wasi target.

I was looking at the Supported Platforms and wasm32-wasi is indeed supported...but the table says that the target has not been tested.

A few questions (with some implied requests):

  1. What would it take to get wasm32-wasi tested?
  2. What does it mean to not be tested?
  3. How stable/production-ready do you consider the wasm32-wasi target?
  4. How stable/production-ready do you consider the rquickjs project in general?
@DelSkayn
Copy link
Owner

DelSkayn commented Sep 6, 2024

Hey!

I consider the wasm target to be pretty stable, it is marked as not tested as I don't have any CI set up to run the rquickjs test on a wasm platform. That said rquickjs is used in javy a tool for running javascript in wasm from the wasmtime people which I take as a pretty good endorsement.

In general I think rquickjs itself is also pretty stable/production ready. It is used by some relatively large projects like SurrealDB and LLRT which seem to use it without much problems. I however don't think this library will every be fully semver stable as it is tied to QuickJS which doesn't follow semver and could introduce some large changes which rquickjs will have to respond to.

@lastmjs
Copy link
Author

lastmjs commented Nov 6, 2024

Hi, how involved would it be to get the CI set up to run the rquickjs tests on wasm32-wasi? We would like to go production-ready with our framework which uses rquickjs, but would love to see this test suite passing first.

@lastmjs
Copy link
Author

lastmjs commented Nov 19, 2024

We might be able to do a PR for this with some guidance

@DelSkayn
Copy link
Owner

I consider a platform tested in the table if the rust tests are run in CI. So we would need some way to run these tests in web-assembly. I haven't had the time to look into how to do that. CI would have to compile all those test to web assembly and then run those in some wasm runtime. There might be some tools already out there to do that, I know wasm-pack has the ability to run tests in wasm but that is specifically for the browser.

@lastmjs
Copy link
Author

lastmjs commented Mar 5, 2025

I'm going to attempt to get the wasm32-wasi test infrastructure setup. I will PR my results. Is there a better way to reach out to you for questions/guidance @DelSkayn?

@lastmjs
Copy link
Author

lastmjs commented Mar 8, 2025

Alright here is the PR, opened as a draft, for some feedback: #441

I've left my main questions as a comment in the PR. @DelSkayn I am very eager for your feedback and to get this merged, as we would like to consider rquickjs production-ready and stable for our own project, and we've decided that these tests are a prerequisite.

@lastmjs
Copy link
Author

lastmjs commented Mar 15, 2025

In addition to my PR @DelSkayn, I have another question about production-readiness.

Is rquickjs's implementation of the event loop/job queue (tasks, micro tasks, macro tasks, etc) robust? My understanding is that this is not part of the ECMAScript specification. Will it follow V8? Chrome? Node? SpiderMonkey? I would love more information on rquickjs's event loop implementation.

We kind of just scatter this code throughout our codebase where we think it makes sense...

pub fn run_event_loop(ctx: Ctx) {
    while ctx.execute_pending_job() {}
}

Is there a danger to calling while ctx.execute_pending_job() {} too often or in the wrong circumstances? We aren't using any of the Rust future code from rquickjs, we just create Promises in JavaScript, store the resolve/reject callbacks in global variables, and from Rust, with our own future code, we will execute the resolve/reject callbacks.

@lastmjs
Copy link
Author

lastmjs commented Mar 15, 2025

One more thing: can we use AsyncRuntime, which I assume uses the futures feature, in wasm32-wasip1 and wasm32-wasip2? I tried this a bit ago and gave up at the time for some reason, I don't remember why.

If this is possible, are there tests? I would like a test suite for this in the Wasm targets ideally.

@lastmjs
Copy link
Author

lastmjs commented Mar 20, 2025

I want to confirm that AsyncRuntime can be used in wasm32-wasip1. Though we have decided not to use them for the time being, as our environment allows us to create promises from a regular Context and perform asynchronous operations in a way that integrates better with our environment.

@lastmjs
Copy link
Author

lastmjs commented Mar 20, 2025

In addition to my PR @DelSkayn, I have another question about production-readiness.

Is rquickjs's implementation of the event loop/job queue (tasks, micro tasks, macro tasks, etc) robust? My understanding is that this is not part of the ECMAScript specification. Will it follow V8? Chrome? Node? SpiderMonkey? I would love more information on rquickjs's event loop implementation.

We kind of just scatter this code throughout our codebase where we think it makes sense...

pub fn run_event_loop(ctx: Ctx) {
while ctx.execute_pending_job() {}
}
Is there a danger to calling while ctx.execute_pending_job() {} too often or in the wrong circumstances? We aren't using any of the Rust future code from rquickjs, we just create Promises in JavaScript, store the resolve/reject callbacks in global variables, and from Rust, with our own future code, we will execute the resolve/reject callbacks.

In our environment, we have requests coming in essentially to a Wasm server environment (Internet Computer Protocol), and when a request comes in we execute a JavaScript function within one Runtime with one Context that lives for the entire duration of our program.

At the end of each request, after the JavaScript function is executed to completion, we call run_event_loop. Also, we have a concept of requests originating from one of our application instances to another, we call these inter-canister calls. When one of these requests returns, it essentially executes another incoming request to our environment. We also call run_event_loop at the end of that execution.

Essentially we attempt to run run_event_loop at the end of each high-level JavaScript function execution, as soon as control is yielded back to the Rust environment.

Does this sound correct? Is running ctx.execute_pending_job() in a while loop what we're supposed to do? Just drain the queue? What about tasks, micro tasks, etc?

@DelSkayn
Copy link
Owner

Is rquickjs's implementation of the event loop/job queue (tasks, micro tasks, macro tasks, etc) robust? My understanding is that this is not part of the ECMAScript specification. Will it follow V8? Chrome? Node? SpiderMonkey? I would love more information on rquickjs's event loop implementation.

QuickJS itself implements the event loop, Ctx::execute_pending_job is just a small wrapper around QuickJS's JS_ExecutePendingJob.

Within QuickJS the 'event loop' is just a linked list of pending jobs. Whenever a promise or something similar is created it will be pushed onto the list and then ran whenever JS_ExecutePendingJob is called.

I don't think there is any issue with calling it frequently.

@DelSkayn
Copy link
Owner

One more thing: can we use AsyncRuntime, which I assume uses the futures feature, in wasm32-wasip1 and wasm32-wasip2? I tried this a bit ago and gave up at the time for some reason, I don't remember why.

That should be possible, if it isn't than it might be a bug.

@DelSkayn
Copy link
Owner

In our environment, we have requests coming in essentially to a Wasm server envir.....

That seems like a fine approach I don't see much anything wrong with it.

Is running ctx.execute_pending_job() in a while loop what we're supposed to do? Just drain the queue? What about tasks, micro tasks, etc?

QuickJS by default only has micro-tasks. If I remember the terms correctly micro-tasks are promises and suchs and macros-tasks are incoming events like in the browser click events and setTimeout. QuickJS does not implement setTimeout or any functionality which results in events like IO so there are no macro tasks.

Calling execute_pending_job will then run all the micro-tasks (promises). So I think for your use-case that is sufficient.

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