Continuous running scripts

My ignition project has about 10 different scripts.

I need all 10 scripts to be running constantly on its own thread(when it finishes executing, a new thread fires and executes again).

Only 1 copy of each script can be running(no 2 same script can be running at the same time).

On ignition failure/shutdown/startup/reboot, all 10 scripts should fire up again.

So far, I am handling it by.

On my gateway startup script I have something like.

system.util.invokeAsynchronous(lambda:scriptA.run())
system.util.invokeAsynchronous(lambda:scriptB.run())
system.util.invokeAsynchronous(lambda:scriptC.run())
system.util.invokeAsynchronous(lambda:scriptD.run())
...

On my project library section I have this on each of my scripts. It will check the tag and see if it is running. If it is not then it will run.

def run():
	import time
	def script():
		if not system.tag.readBlocking('[~]SCRIPT_A_ACTIVE')[0].value:
			system.tag.writeBlocking('[~]SCRIPT_A_ACTIVE', True)
			code()
			time.sleep(1)
			system.tag.writeBlocking('[~]SCRIPT_A_ACTIVE', False)
			system.util.invokeAsynchronous(lambda:script())
				
	system.util.invokeAsynchronous(lambda:script())

On my gateway shutdown. This is to reset the tags so when ignition starts up again, the scripts will run again.

system.tag.writeBlocking('[~]SCRIPT_A_ACTIVE', False)
system.tag.writeBlocking('[~]SCRIPT_B_ACTIVE', False)
system.tag.writeBlocking('[~]SCRIPT_C_ACTIVE', False)
...

Is there a better way of doing this? Is the way I am handling it correctly done?

How truly continuous do they need to be? i.e. how tight does the loop need to be?

Creating 10 timer scripts configured for dedicated threading would be the easiest way to not screw this up.

Must be continuous or about 1 sec after end.

Originally I was thinking a gateway timer script have it it run there. But this brought 2 potential issues.

  1. Without knowing exactly how long each script can run or taking into account any factors that can delay the code execution time. Lets say I set the timer to execute every 2 seconds and my code finishes executing in 2.1 seconds. Now we have 2 scripts running.

  2. Assuming we handled the above issue with a check to see if the script is running. The script finishes in 2.1 seconds. But at 2 second mark the timer see that it was running so it does not execute. Now between 2.1 and 4 seconds, no scripts are running.

Each of the 10 scripts we cannot give a set time for as we do not know how long each script can potentially run for.

No, that's not how it works.

Kevin's approach is the safest, not using invokeAsynchronous(), and you need to make sure your scripts stop regularly, so that project edits will replace the code.

It's important to understand that gateway startup scripts are not just gateway startup - they are also any time the project is saved and the scripting gets reloaded. This makes for a very difficult to manage lifecycle when you're trying to do everything yourself in the background like this.

Can you expand on this?

The code itself is reading/writing directly from/to the tags. So even if the tags are changed the code will be able to take this into account.

This smells like an XY problem. What are you doing in these threads?

See Gateway Event Scripts | Ignition User Manual

where it describes fixed delay vs fixed rate. In neither case will the same script be overlapping in execution.

In "Fixed Delay", your script runs again at whatever the interval is after the execution finishes.

In "Fixed Rate", your script runs at the fixed interval, but if an execution goes long it does not overlap, the next execution just begins immediately after the previous finishes.

1 Like

These threads are running code logic which performs calculations real time. These calculations can affect tags which other scripts running on other threads will require.

So, like a PLC task? Just run them from gateway timer events at a fast fixed pace, each function being treated as if it were in a PLC.

The function would do the equivalent of one PLC scan's work and return. Set the timer rate appropriately for your application. Follow best practices for multi-threading in PLCs:

  • Use a single system.tag.readBlocking() at the beginning to gather all of the tag values your logic needs into local variables in the function.
  • Perform all of your logic, yielding new "output" values in function local variables.
  • Use a single system.tag.writeBlocking() at the end to send all of the new output values to their actual tags.
1 Like

Oh... I was under the assumption that it will execute the script on a set interval regardless of it completed or not.

If this is the case, by selecting fixed delay it will run script, wait for it to complete, wait for delay milliseconds, run script.

Yes, that's how Fixed Delay behaves.

2 Likes