Replies: 1 comment
-
|
The thing I understood so far, is that "It is safe to use a context instance from a single thread. It is also safe to use it with multiple threads if they do not access the context at the same time.". So basically I'm trying to make access to context through the same 1 thread throughout the program. HOWEVER when this works in JS: JsResult run(Source source) throws InterruptedException, ExecutionException {
CompletableFuture<JsResult> finalResult = new CompletableFuture<>();
// Submit everything to the JS event loop
loop(() -> {
try {
var result = context.eval(source); // Eval runs on gold-event-loop thread
var state = "pending";
if (result.hasMember("state")) {
state = result.invokeMember("state").asString();
}
if ("fulfilled".equals(state)) {
finalResult.complete(JsResult.ok(result.invokeMember("value")));
} else if ("rejected".equals(state)) {
var reason = result.invokeMember("reason");
finalResult.completeExceptionally(
new RuntimeException(reason.toString()));
} else if (result != null && result.hasMember("then")) {
// Promise: attach handlers
result.invokeMember("then", (ProxyExecutable) args -> {
finalResult.complete(JsResult.ok(args.length > 0 ? args[0] : null));
return null;
}, (ProxyExecutable) args -> {
var jsError = args.length > 0 ? args[0] : null;
finalResult.complete(JsResult.error(jsError));
return null;
});
} else {
// Not a Promise, resolve immediately
finalResult.complete(JsResult.ok(result));
}
} catch (Throwable t) {
// Any immediate JS error
finalResult.complete(JsResult.error(t));
}
});
// Pump JS event loop until the result completes (or fails)
eventLoop.runUntil(finalResult::isDone);
// Stop the event loop now to avoid dangling tasks
close();
// Propagate exceptions to caller
return finalResult.get();
}With top-level await, the result is gotten immediately as pending promise (top-level) and the event loop is freed so that other promises can get resolved, but in Python, similar code PyResult run(Source source) throws InterruptedException, ExecutionException {
CompletableFuture<PyResult> finalResult = new CompletableFuture<>();
loop(()->{
try {
var result = context.eval(source);
finalResult.complete(PyResult.ok(result));
}catch(Throwable err) {
finalResult.complete(PyResult.error(err));
}
});
eventLoop.runUntil(finalResult::isDone);
return finalResult.get();
}does not even work, because context.eval on top-level code that called asyncio.run, blocks the whole of the event loop, making it impossible to resolve inner futures which are prerequisite to resolving the top-level one... it's basically a dead-lock, which does not happen in JS because context.eval returns a promise. // event-loop related
void loop(Runnable callable) {
eventLoop.submit(callable);
}
private void loop() {
try {
while (running.get()) {
var task = queue.take();
currentTask = task;
context.enter();
try {
task.run(); // the task in python doesn't get complete because it's the main loop started by us or something.
} finally {
context.leave();
}
}
} catch (InterruptedException ignored) {
// System.out.println("error 100 in the event loop");
}
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
For GraalJS, there's a section on Promises in the documentation:
So I've tried similar with Python, given a script
and an adapter:
In Java, we create a future:
With the Java-based APIs:
I've spent an entire weekend hacking and it just gives inconsistent results... Sometime it run, other times it doesn't... When the promise is resolved on the same tick (during debug, returning an already finished future), it's fine but it's pending first, it stops working
but when the promise is pending initially, it gets stuck
Is there more docs on futures and how i can return promised returns from my java infra?
Beta Was this translation helpful? Give feedback.
All reactions