I recently was made aware an issue that got me thinking about scripting in asynchronous contexts in Ignition.
In this case, blocking functions such as sleep and system.tag.writeBlocking were being used in tag event scripts and appeared to be causing problems.
The proposed fix was to move that work into system.util.invokeAsynchronous.
The recommendation implied a few things to me, based off my experience with other languages and async runtimes:
- Tag event scripts execute in a shared execution context with other scheduled tasks.
- Blocking operations in that context can prevent other scheduled tasks from making progress.
system.util.invokeAsynchronousis intended to offload long-running or blocking work onto a thread pool where blocking is acceptable, so that the original execution context can continue.
In general, the main reasons I would expect to want to block a thread are:
- Expensive CPU-bound work
- Synchronous I/O
Those are the situations where I would expect to reach for something like system.util.invokeAsynchronous.
My questions are:
- Are my assumptions sound?
- If so is there documentation or guidance describing which Ignition scripting contexts users should avoid blocking in?
- Is there a need for more general education around this topic: what blocking means, when it is acceptable, and what are the strategies for managing blocking tasks?
One related thought I have is if the idea "write a value and wait" is a common anti-pattern. My understanding is that system.tag.writeBlocking waits for the write operation itself to complete, but that does not necessarily mean the new value has already been published back through the tag system. If a script then sleeps for some guessed amount of time hoping the value will update, that seems fragile. Even if that logic is moved to a thread where blocking is acceptable, it also seems like it could become problematic if many of these tasks stack up.
I would appreciate any clarification. I suspect part of my confusion is trying to map concepts from other runtimes/frameworks onto Ignition without fully understanding how Ignition manages these execution contexts internally.