openhab-addons: [jsscripting] Multi threaded access is not allowed for language(s) js.
Using openHAB 3.2 in two /etc/openhab/automation/js/*.js files I have:
class R {
constructor(z) {
this.item = items.getItem(z)
}
get isOn() {
return this.item.state == "ON"
}
turn(state) {
this.item.sendCommand(state)
}
}
const ri = new R('i'), rz = new R('z')
rules.JSRule({
name: 'ABC',
description: 'ABC',
triggers: [
triggers.ItemStateChangeTrigger('A', null, "0 W", "Y1"),
triggers.ItemStateChangeTrigger('B', null, "0 W", "Y2")
], execute: (data) => {
console.error('M', ri.isOn, rz.isOn)
ri.turn('OFF')
rz.turn('OFF')
setTimeout(() => console.error('N', ri.isOn, rz.isOn), 1000)
setTimeout(() => console.error('P', ri.isOn, rz.isOn), 2000)
}
})
Running the script logs:
2022-06-26 16:56:25.132 [INFO ] [org.openhab.automation.script ] - M true true
2022-06-26 16:56:28.550 [INFO ] [org.openhab.automation.script ] - N false false
2022-06-26 16:56:28.504 [WARN ] [ore.internal.scheduler.SchedulerImpl] - Scheduled job failed and stopped
java.lang.IllegalStateException: Multi threaded access requested by thread Thread[OH-scheduler-22,5,main] but is not allowed for language(s) js.
at com.oracle.truffle.polyglot.PolyglotEngineException.illegalState(PolyglotEngineException.java:129) ~[bundleFile:?]
at com.oracle.truffle.polyglot.PolyglotContextImpl.throwDeniedThreadAccess(PolyglotContextImpl.java:940) ~[bundleFile:?]
at com.oracle.truffle.polyglot.PolyglotContextImpl.checkAllThreadAccesses(PolyglotContextImpl.java:799) ~[bundleFile:?]
at com.oracle.truffle.polyglot.PolyglotContextImpl.enterThreadChanged(PolyglotContextImpl.java:629) ~[bundleFile:?]
at com.oracle.truffle.polyglot.PolyglotEngineImpl.enterCached(PolyglotEngineImpl.java:1885) ~[bundleFile:?]
at com.oracle.truffle.polyglot.HostToGuestRootNode.execute(HostToGuestRootNode.java:112) ~[bundleFile:?]
at com.oracle.truffle.api.impl.DefaultCallTarget.callDirectOrIndirect(DefaultCallTarget.java:85) ~[bundleFile:?]
at com.oracle.truffle.api.impl.DefaultCallTarget.call(DefaultCallTarget.java:102) ~[bundleFile:?]
at com.oracle.truffle.polyglot.PolyglotFunctionProxyHandler.invoke(PolyglotFunctionProxyHandler.java:154) ~[bundleFile:?]
at com.sun.proxy.$Proxy701.apply(Unknown Source) ~[?:?]
at org.openhab.core.model.script.actions.ScriptExecution.lambda$1(ScriptExecution.java:100) ~[bundleFile:?]
at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$12(SchedulerImpl.java:184) ~[?:?]
at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$1(SchedulerImpl.java:87) ~[?:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: com.oracle.truffle.api.TruffleStackTrace$LazyStackTrace
(the above is logged twice, since I have in two distinct .js files nearly identical code). The second exception starts with 2022-06-26 16:56:28.522 [WARN ] [ore.internal.scheduler.SchedulerImpl] - Scheduled job failed and stopped and is thus called after the console.log('N') code.
- The timestamps do not strictly increase in the
/var/log/openhab/openhab.logfile. - There shall be no
Multi threaded access requested by thread Thread[OH-scheduler-22,5,main] but is not allowed for language(s) js.exception. JavaScript is single threaded, setTimeout() does not necessary add a new thread. - The error message does not suggest which script/JSRule caused the exception.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 33 (21 by maintainers)
I will double the bounty to 200€. @jpg0 would it be possible to add the ‘bounty’ label ?
@tarag: Good news. I got it working without using some MultiTimerMock workaround.
I am using the following script to verify threadsafety of both triggered rules (so that I did not brake anything) and of scheduled jobs/timers:
As you can see, creating 100 timers with the same timeout would for sure generate many errors if there was not somy sort of synchronization. But, the synchronization avoids that and makes all scheduled jobs run without any issues:
View my logs
@jpg0 My implementation is not exactly what you were talking of in your last comment, I am “only” using a shared lock mechanism for scheduled jobs and rules. I haven’t tried wrapping the Context as I currently don’t see where to do that correctly.
That are quite interesting questions, but currently I don’t have the time and I also don’t have the knowledge to investigate that and introduce some sort of event loop.
Looking at the changelog, I don’t see changes related to that. Their example for multithread access is also using a lock, so currently I don’t expect GraalJS to have a built-in solution.