Open larsrh opened 4 years ago
Hi @larsrh, JSAgent
is an internal implementation class, and we cannot expose it to user applications. In our concurrency model, the user application needs to ensure that no concurrent access on objects belonging to the same Context
can happen. In this article we have a few examples showing how multiple threads can use promises concurrently
Of course; I'm not arguing that JSAgent
should be exposed just like that.
The article you linked isn't applicable in my scenario. The application is started through node
, which means that the Context
(and execution thread) is fully in control of the Node REPL. It is impossible to run any other code on that thread. Of course I could use synchronized
or other things if I were to create a Context
(or a pool) myself, but I don't.
Addendum: You can imagine my feature request like a setImmediate
equivalent that I can call from Java.
You can do that. Check out https://mikehearn.github.io/nodejvm/ or the articles in the GraalVM Medium blog. The linked program inverts NodeJS support so the JVM runs first, but it shows how to relay Java calls into the NodeJS thread with some transparency. The trick is to create a worker in the NodeJS world and then attach it to a Java LinkedBlockingQueue onto which you push closures. You can then schedule any Java closure to be executed in the NodeJS thread. It would of course be nice if the NodeJS GraalVM integration was more direct, but it is not too difficult to do this.
I'm not sure if this comment exactly reflects the desire of this issue (I'm happy to open a new one), however I think that it's important to disambiguate between: support for setTimeout
(which implicitly requires an event loop), explicit introspection/management of the event loop, and support for other nodeJS APIs. These often seem to get mixed up and/or combined.
I would like to state that I believe that the first (support for setTimeout
) should be part of the embedded JS runtime because it's part of every other JS runtime out there (including all the browsers). Lots of pure-JS things like Promises can be built on this.
The second thing (introspection and management of this loop) is something which could later be added, but I'm not sure it's expected so universally. (I don't personally need this.)
The last thing (general nodeJS APIs) is clearly a much larger endeavour here which should not be mixed up with the event loop which isn't node-specific afaics https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop.
I'm running some JS code through the Node binary that's shipped with Graal. This code calls to some async Java code. I use a similar trick like in the GraalJS tests to convert a Java
CompletionStage
to a JSPromise
:https://github.com/graalvm/graaljs/blob/278b71516f85fec61a5ca35353ab31dc637f31db/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/AsyncInteropTest.java#L211
Unfortunately, if the
CompletionStage
is completed on another thread, this fails because of concurrent access to JS objects.The
JSAgent
class contains the top-level callback-loop for Node:https://github.com/graalvm/graaljs/blob/vm-20.1.0/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSAgent.java
It would be gread if Java user code could dispatch callbacks on that loop. This would solve the concurrent access problem: I could register a handler on the
CompletionStage
that, instead of resolving the Promise directly (on the wrong thread), would schedule the resolution on the main Node thread.