I don’t have “a plan” for how it could be used, but from what I understand, you can handle objects from another context without getting the multithreaded exception if you have “entered” that context.
I’m not sure as per now if “entering” the context is different from locking our “context lock”, but I’d sort of assume that it would work better to use the lock that GraalVM itself has created and is using. But, let’s forget about that for now, that’s a too long path to solve this anyway, and might result in the same deadlock situation that we’ve been trying to avoid.
Have you looked at my javaify() method? I think that could solve the passing of parameters to another rule.
Do you guys think that it’s likely there will be a resolution to the “Multi threaded access requested by thread Thread[#8260,OH-rule-AlarmNotifier-1,5,main] but is not allowed for language(s) js.” issue in the near term? I have 6-8 rules from this template that are now failing. If not, I’ll look at a longer-term work-around, possibly using executeCommandLine() to shell out and do the notification from an external script, if I can pass it all of the parameters.
It depends on when the fix will be reviewed and merged, and a new JS library released. I’d say that it depends on what you see as long/short term.
Depending on what your situation is, you can possibly get some of them to work in the meanwhile by not sending JS objects via runRule(). I’d say that should be an easier fix that executeCommandLine() in any case. If you have to send an object, create a java.util.Map instead, of you need so send an array, create a java.util.List instead. That’s basically what the fix will do for you.
It is a ZIP file, so just remove the .txt extension (that’s just to get the forum to accept it), and inside you’ll find 4 files. I think that you only need one of them, but I’m not sure how this works.
@rlkoshak I’ve just published openhab-js 5.19.0 with utils.javaify and utils.jsify functions - javaify is automatically called when passing context to rules.runRule, jsify has to be called manually currently.
I’ve got a port of this template started. I’ll try to get this tested today or tomorrow depending on how the day goes and the porting of the template goes. For now I’m just passing Strings and bools so it shouldn’t be too much to restore the array and test with the updated library.
This should probably be mentioned in the 5.2.0 release thread, so that all those with these problems can update openhab-js manually and hopefully solve these problems…
I don’t know the answer to the question, but they should generally work well with the shared cache, and perhaps javaify() should be automatically applied when putting into the shared cache as well. As for the private cache, JS objects are fine, so it shouldn’t be touched IMO.
Somewhat on a tangent here, but do we need Blockly blocks for javaify() and jsify() as well? Or is there some other “convenient” way Blockly users can use them? I already have a pending PR for some Blockly block I’ve added, if this PR turns out to be valid/correct, I could probably manage to add blocks for these as well.
Only if you jsify on the receiving end automatically which becomes challenging. How do you know what went in was originally JS and not Java?
Yes. Otherwise Blockly won’t be able to send nor receive in a way that can be processed by the rest of the blocks.
Though for Blockly you might be able to add the JS code to call these to the runRule and get ctx blocks so it happens transparently. The challenge will be knowing when to call jsify automatically on the receiving side.
This isn’t what is done when you run rules, and I’m not sure that it should be done for the cache either. There are some differences between the two:
Sharing JS objects between threads will fail, so it must be avoided, even if that means “loss of data”.
There’s no way to differentiate between what should remain a Java map and what should become a JS object, so Java maps that you might need to keep that way for use with other calls, must be retained somehow. By making the call to jsify() explicit, you also provide access to the Java objects, should that be needed, which allows a “liberal conversion” from Java maps to JS objects in jsify().
runRule() already calls javaify() automatically in the helper lib, so there should be no need to do anything in Blockly there. When it comes to automatically calling jsify() on the other side, I can’t see how that can be “figured out”.
I think jsify() must remain a manual step on the received context, and that’s not actually such a bad thing, because you can get context from other sources than other JS scripts, and it would give you to ability to “jsify” anything, regardless of source.
I’m Joe Schmoe user and I put a JS Array of Strings into the arguments passed un runRule or into the shared cache.
In the other rule I pull out that value but loe and behold, I cannot us it. It’s now a Java List. None of my usual JS ways of working with it will work.
This surprises me (still speaking as Joe Schmoe here). Why isn’t it what I passed? How do I change it so I can work with it (note, utils really needs to be added to the JS Scripting docs now that it includes methods that average end users will have to deal with)?
It is less surprising to get an error up front or to get an error before the called rule is called than to wait until you get to the called rule to discover that you recieved a valid Object but it’s different from what you passed in.
So it is better over all in my opinion to require explicitely calling javaify on the calling side and jsify on the receiving side than it is to explicitely call javaify but still require jsify.
I didn’t realize that. I though one still needed to call javaify. If it’s not converted back on the other side I don’t like that much. Not that I expect it to change, but I don’t like spooky magic that needs to be undone manually.
This certainly would qualify as a breaking change I think. It should be documented as such.
I can see several options that could work. But don’t want to argue about it and I’ve not fully thought it through from a Blockly and other rules languages perspective. But at a high level it would involve the library adding a “private” map to the context that keeps track of those Objects that needed automatically calling javaify. On the receiving side the library checks that map and calls jsify on those Objects that need it, replaces the Objects in the context with the js versions and strips off the “private” map.
This is the only way to make all the existing scripts that produce multithreaded access errors “solve themselves” without having the users change the scripts, and also, it’s pointless to not call it - because sending JS objects to runRule() will always fail.
How is it breaking? It’s “unbreaking” if anything. You can’t send JS objects across threads, that’s not new. What is new is that other rules run in their proper thread, but the fact that it wasn’t before was always a bug that just “happened to work out” for this specific scenario, but that broke other things. So, if a “breaking” warning should exist here, it would have to be for 5.2.0, that no longer allows this “bug exploit” to work.
Except it doesn’t do that. It just moves the error from the calling rule to the called rule. Now the called rule now throw errors because it cannot process the received data the same way as it was before becuase now it’s Java.
Because the users still need to change their scripts. At a minimum they need to manaully add calls to jsify.
Except we were and it was working before the called rule was given it’s own thread. So we could quibble and say that that was the breaking change.
Either way, we have an undocumented breaking change. Something that worked for most people most of the time now doesn’t work for any user any of the time without changes to their config.
Even if it’s a bug fix, the fact that users must change their scripts to restore what used to work (even if only most of the time) makes it a breaking change.
Yes, but it was a “breaking change” that nobody was able to predict it seems, which is why we’re in the situation we are now, with an undocumented “breaking change” that has already occurred. I’m not saying that there shouldn’t be any information about this, just that I’m not entirely sure how we should go about doing it now, after the fact. Perhaps @florian-h05 has some idea?