Yes, we became more strict about Perspective’s threading model.
You need to submit your extension function invocation to the work queue.
One way to do it is the new PerspectivePollingFuture class; for the alarm status table we create one in the model delegate in the constructor:
Oke what do i do with the querypoll once i created one in the constructor?
Ahh the fetchAlarmStatusFuture points to somethign about the Blockingoworker…
andthe this::receaiveAlarmStatus points to a function with invoke…
phew this got quite a bit more complicated xD
Is the defaultrate how often it checks the extension function exists or what do i make of that?
Cuz normaly i only invoke the extensionfunction on a specific handleEvent. i dont really want to poll to this function, just execute it one time when the clientside send a specific message. which really wont happen often
Yes, since we added that class in 8.1.12 you’ll have to bump your SDK dependency version(s) to that. You’ll also want to bump the minimum required version of your module to at least that SDK version, so that someone can’t attempt to install your module on an older gateway (which would invariably fail, due to the missing classes).
You might be able to get away with a simpler strategy - post a Runnable (probably a lambda) to the common queue, e.g.: queue.submitOrRun(() -> fireEvent(ResponseEvent.DATA, asJsonObject("fetchUrl", fetchId)));
If you invoke your extension function on queue, you shouldn’t get that error message.
Disclaimer: I’m mostly just reading the code and aware of some background here, this is not my area of expertise.
Hm i need to use runOrSubmit to get the return value, but even doing so im still getting the blocking error i notice the error is now on a much lower queue (1 or 2) compared to last time (40+) though that might be unrelated or just because the server hasnt run that long yet xd
I havent updated the sdk yet tho or included anything about the blocking
Do i need to do something else here? the snapshot of gradle? where can i find what path i need?
So i tried updating sdk again and noticed it continued downloading where it left of…
it gave an similar error with some other numbers but the same file.
then i did it again and it downloaded it fully and now it builds xd
.join() is a blocking operation, so I think you are just cheating. I don’t know enough about the queuing rules to say if that is safe. I would expect you to put the assignment to openDefault in the runnable. Possibly needing synchronization, though.
I never wanted/needed this to be in a seperate thread,
but with the new update (8.1.12+) it seems extensionfunction.invoke automatically gets created in a new one, because so far igntion only used it for polling functions, but i do not use it for that purpose.
Alright it seems this is causing some unexpected problems afterall…
for some reason i can not access any params or props inside my extension function.
When i call one it seems to get stuck infinitly, i can see the script running in diagnosics running scripts.
The server gets completly stuck even after canceling the script, forcing me to restart, yet no logs or errors are shown.
even something as simple as a print, gets stuck on the view param line.
Ive tested this in the alarm component and there it does work. Seems im blocking the async props call somehow and it keeps waiting for it to respond?
I doubt this has anything to do with me “joining” the thread tho…
And probably more with how i create the runnable thread itself with the blockingwork…
any idea how i could do this differently?
Do i maybe have to use wrapThreadFactory?BlockingTaskQueue? if so how?
Solving these sorts of problems usually means rethinking the movement of data through your logic, so that the problem item is already “present” when requested. And you deliver it without blocking. If stale, the caller gets the stale value.
Your comment that it probably isn’t the “joining” seems outrageously unlikely to me.
I mean i could move along this one prop through the data flow… but who knows next weeks its a different prop…
The fact that is works normally for the alarms status means the self.view.props should be accesable in extension functions somehow.
Maybe it is? i do not have all that much experience with threads in java (or in general).
i thought it just waits for it finish what its doing, should not also wait for any async (prop) calls inside its thread aswell?
The PerspectivePollingFuture mentioned above automatically handles the subscription to the properties.
The Supplier<CompletableFuture<V>> fetch is a computed function that returns a CompletableFuture (think Promise) containing your result type V. Then BiConsumer<V, Throwable> consumer will be invoked when your future completes, with either your result type Vor some exception that was thrown during the fetch.
That BiConsumer will be called on the Perspective executor pool that allows ‘blocking’ work automatically, so you’re allowed to invoke whatever extension functions you want.
So ive been digging into the polling future and found an easier way to call the invoke.
I was almost like you said here:
but instead of running it on the queue, i run it on the executor.
This by passes all the blocking and threading problems component.getSession().getPerspectiveContext().getExecutorService().submit(()-> ...invoke(...)).get()
However im still getting frozen on calling session props. I looked at the pollingfuture and it did not seem to provide the props to executor service or something. OR maybe i have missed it, im looking a bit more into it and will update this post if i find something
Alright so insteadof print(self.view.params.key) i did print(self.view.params.get(‘key’))
and im getting the print of the prop after the event and the event is returning nothing
So it seems like Future.get() is not waiting for the params.get(‘key’) but waiting infinity on the params.key?
So i guess this also was happening before in the thread i made with the joining…
I really dont understand this…
How would i wait for it to finish?
or do i just put all my code inside the future? Guess ill try that next
There are many situations, and this appears to be one, where you CANNOT WAIT. The original thread does not permit blocking. Any kind of wait is BLOCKING. I’m glad you stumbled on a solution (putting the balance of the code in the executor), but it is frustrating that you can’t accept “Don’t wait/block/sleep” as the answer.
(You could also have put the balance of the code in a .whenComplete lambda on CompletableFuture.)