Open
Description
It is clear that javascript is not supported under multi thread environment, but I suppose some components should handle multi-thread.
- Promise-Like
Promise is good option to express concurrent control flow. However in current implementation we can not resolve Promise from different Thread!. (Except for few case)
(1) NodeJS -> Java
const JvmContextClass = Java.type("com.example.Executor")
const jvmContext = new JvmContextClass()
const myPromise = new Promise(jvmContext);
await myPromise
package com.example
class Executor {
void then(Value resolve, Value reject) {
Executors.newSingleThreadExecutor().execute(() => {
try {
Object someResult = computeSomething();
// Error, NodeJS is holding the context
resolve.executeVoid(someResult);
} catch (Throwable t) {
// Error, NodeJS runtime is holding the context
reject.executeVoid(t);
}
})
// return control of current context back to NodeJS
}
}
Only solution for this situation is to block the nodejs until Java resolve the Promise.
(2) Java -> embedded Javascript
This case is not a problem, since Java developer can synchronize the access to the Context
- NodeJS- microTasks
We cannot queue runnable to the nodejs taskqueue e.g)setInterval
,setTimeout
,setImmediate
when nodejs is taking control. So we cannot use those method to resolve Promise or queue task to notify the nodejs.
const JvmContextClass = Java.type("com.example.Executor")
const jvmContext = new JvmContextClass()
const myPromise = new Promise(jvmContext);
await myPromise
package com.example
class Executor {
void then(Value resolve, Value reject) {
Value setImmediate = resolve.getContext().eval("js", "setImmediate");
Executors.newSingleThreadExecutor().execute(() => {
try {
Object someResult = computeSomething();
// Error, NodeJS is holding the context
setImmediate.execute(() => {
resolve.executeVoid(someResult)
}).asInt();
resolve.executeVoid(someResult)
} catch (Throwable t) {
// Error, NodeJS runtime is holding the context
setImmediate.execute(() => {
reject.executeVoid(t);
}).asInt();
}
})
// return control of current context back to NodeJS
}
}
NodeJS task queue api and Promise-like object needs to support multi-threading out-of the box.
Creating nodejs worker thread to resolve one promise seems like pretty expensive.
Work Around
I make a workaround using Worker and Blocking Queue.
But it would be nice to use, something that nodeJS event loop can poll it, rather than blocking.
And still can not schedule task to NodeJS
data object JavaMain {
@JvmStatic
fun main(vararg args: String) {
//
val mainContext = Context.getCurrent()
val blockingQueue = LinkedBlockingQueue<Runnable>()
val uuid = "X" + UUID.randomUUID().toString().replace("-","")
val binding = mainContext.getBindings("js")
val jsScript = """
const { Worker } = require('worker_threads');
const worker = new Worker(`
const { workerData, parentPort } = require('worker_threads');
const assert = require('assert');
while (true) {
parentPort.postMessage(workerData.take());
}
`, { eval: true, workerData: $uuid })
worker.on('message', block => {
block()
});
worker;
""".trimIndent()
binding.putMember(uuid, blockingQueue)
val proxyWorker = mainContext.eval("js", jsScript)
mainContext.getBindings("js")
.removeMember(uuid)
blockingQueue.add{
mainContext.eval("js", "console.log(1234)")
println(proxyWorker)
}
}
}
Metadata
Metadata
Assignees
Labels
No labels