Gateway Timer Event Scripts in 8.0.6

So, we just upgraded from 7.9 to 8.0 and most things are working well.

First things first, the online manual has a typo:
https://docs.inductiveautomation.com/display/DOC80/Gateway+Event+Scripts

The timer scripts example has a Hello World example that will not compile
system.util.getLogger(“TestScript”).info.(“Hello”) should be
system.util.getLogger(“TestScript”).info(“Hello”)

To get to the more complicated issue, I’m seeing our Gateway timers executing far more rapidly than they should be. We have some timer tags, that are toggled by Gateway Timer Event Scripts, and these are used for simple tasks like repeating an alert .wav file for Alarming purposes.

After the update, we saw that the timed events were running with no clear periodicity. Investigating, it seems like the scripts are being executed multiple times in the same second, and overwriting each other. To avoid any question about effects of the upgrade, I wrote a brand new gateway timer script, exactly as in the manual, and ran it. It should have written to the logs once per second. Instead, we got 14 executions in 1 second!

Changing the delay has some effects, changing it from 1,000ms to 10,000ms takes us from 14 executions per second to 4 executions per second. Going from 10,000ms to 40,000 gives us… 4 executions per second. 100,000ms gives us 4 executions per second.

What could be causing this?

Finally, system.tag.write() seems to have been deprecated. The manual does not make clear the distinctions between system.tag.writeBlocking() and system.tag.writeAsync(). Can anyone explain them, and which function is the correct choice for a quick, regular write to a ‘timer’ tag, with 1-2 second periodicity?

Well, the difference is in the name :slight_smile:
Basically, unlike system.tag.write() in 7.9, if you perform a tag write with system.tag.writeBlocking(), then you are guaranteed that the next line in your script will not execute until that write has either completed, or thrown an error. Whereas writeAsync(), like write(), merely dispatches a write to the executor service, and does not guarantee a result. Where writeAsync is strictly an upgrade over write(), though, is when attempting to do something 'out-of-band'. writeAsync lets you pass a "callback" function, which means you can do something whenever the write result comes back, if you don't care about strict timing. In 7.9, system.tag.write() simply dispatched to a queue...but there was no way to wait for that write to actually happen later.

As for what’s happening with your timer scripts: what project are you configuring these scripts in? Is it inherited by any other projects?

I’m configuring the scripts in global, since I want it to be a gateway level event. I want there to be a set of boolean tags that toggle, regardless of whether any of the projects that will check on those tags are running.

‘Global’ is inherited by most other scripts. I didn’t create it, it seems like certain global properties from 7.9 had been repackaged into a ‘gobal’ project, and given as an inheritance to all other projects. Alarm pipelines, gateway event triggers, shared script folders, things of that nature.

However - that should not matter. I created a brand new gateway level script. It isn’t called by any other projects, it interacts with nothing. It prints ‘Hello’ to the logger and returns None. It should be called once per second, or once per ten seconds, or once per 40 seconds, or once per hundred seconds, because that’s what the setting on Gateway scripts, timed events tells it to do.

I have been unable to get it to execute less than 4 times per second. Any help would be appreciated. I don’t want to have to cook up some while loop to keep my alarms beeping while an alarm condition is high, and potentially eating up too many resources, when it seems like there’s something to do specifically that available.

Also, for maintainable code, having my alarms bound to tag ‘TwoSecondTimer’, which is itself written to by a single shared script called ‘TimerManager’ will be easier than writing a specific script for each component across every project.

Is there a reason why there is so much ‘Restarting gateway scripts…’ spam in the logs?

I’m not saving and updating at those times, it’s just happening.

If you edit scripts in a parent project, all child projects have to restart to get the changes. Similar to editing shared scripts in v7.9–all projects would have to restart.

Sounds like you need a special project, that isn’t a parent for anything, that will hold your global scripts. And possibly make it the gateway global scripting project, so your tag events can use it. Then you won’t be disturbing other projects.

Thanks Phil,

I’ll give that a shot. Edit: I’ve since found that there’s no easy way to copy/paste or drag/drop these scripts from ‘global’ to ‘GatewayEventScripts’ (my new inheritable project). The error message is ‘no drop current’. It would be nice for that option, given that this is something anyone who will upgrade from 7.9 - 8.0 who used shared scripts will need to do.

One issue that may be presenting, or perhaps I don’t know what I’m doing: I tried to run this script in a client timed event script.

I don’t seem to be getting anything posted to the logs, and have both turned the project to ‘play’ on my designer after saving and pushing changes, and after also updating the single client running the project. I’m not sure why a client timed event wouldn’t be heart-beating to the logs when set to do so every second.

Any thoughts?

Did you look in the client’s own diagnostics? Logging in a Vision client and in the designer do not go to the gateway log.

Good call.

Ok, so. I took a project, wrote a Client Timer Event with the following code:

testval = system.tag.readBlocking(['[default]OpsPLC/Test'])[0].value
print(testval)
testval += 1
system.tag.writeBlocking(['[default]OpsPLC/Test'], [testval])
system.util.getLogger('test').info('running')

And I see the ‘test’ tag increment once per second, per running client, as expected, and the log notes are logged at the proper rate.

I THEN go to my new, inheritable project GlobalEventScripts, and paste the same code into a Gateway Timer Event with the same 1 second rate. I see nothing happen.

I THEN go to the inheritable project ‘global’, which I did not create, which was created during the upgrade from 7.9 to 8.0, and paste the same code into a Gateway Timer Event with the same 1 second rate. I see the 10+ writes per second.

What could be causing this behavior? What has changed about how gateway events and shared scripts are handled in the new version? It seems like ‘global’ is the only valid source for gateway events, despite the fact that Gateway Events and shared codes are available (not greyed out as they are in other noninheritable projects) in both inheritable projects?

Also, saving changes to ‘global’ takes significantly more time (about 10 seconds total) than saving any other project, which seems to be related to how it spams many (40, having just tried) ‘restarting gateway event scripts’ messages to the console and logs during the process.

Also of note: starting up the designer and opening a project puts the following messages into the console:

13:37:24.509 [AWT-EventQueue-0] ERROR Scripting.ScriptManager.Glow - Warning: collision at system.util.initialize
13:37:23.967 [DesignerExecEngine-1] WARN tags.subscriptions - Subscription crc mismatch, will resubscribe.

I can’t find information on system.util.initialize. I think it’s likely this is related, or at least nothing good.

If you define a Timer Script in global (an inheritable project), then every project that inherits from global will have that Timer Script and start running it.

Your global project, or GlobalEventScripts, should contain shared script libraries, NOT timer or other event scripts, unless you want the children of that project to all be executing their inherited copy of that event script.

Ok, thanks.

Real quick though. I didn’t define anything in global (an inheritable project).

global (an inheritable project), was created for me upon upgrading from 7 to 8. It then arrogated to itself all previously shared resources, and started running them in ways that were not previously intended.

I want my gateway event scripts to run on one computer only, the gateway. I want them to run on the gateway because I want them to always run, independent of whether a particular program is on, and I want them to run only one time. The timer scripts I wrote are Gateway Event Scripts.

From the 8.0 manual, emphasis mine:

“Gateway Event Scripts Overview
Gateway Event Scripts are scripts that run directly on the Gateway. They are useful because they always run, regardless if any sessions or clients are open. They also provide a guaranteed way to make sure only a single execution of a particular script occurs at a time, as opposed to placing a script in a window, as there could be multiple instances of the window open at a given point of time.”

It sounds like what I need to do, as a user who had Gateway Event Scripts running on the gateway in 7.9, is to remove them from global. Then create a non-inheritable project, called, for instance, Gateway Events and create a Gateway Timer event and store my Gateway event scripts there.

Otherwise my Gateway event scripts won’t run directly on the Gateway, will regard whether sessions or clients are open, and will not guarantee only a single execution of a particular script occurs. Correct?

Gateway Event Scripts will run on the gateway regardless of what project they are defined in.

I’m pretty sure 7.9 didn’t allow you define Gateway Event Scripts on the global project. Shared script libraries, sure, which your Gateway Event Scripts from various projects could have all been calling.

So I’m not sure how you could have ended up with any Gateway Event Scripts (timer, startup, shutdown, etc…) defined on the “global” project that gets created on upgrade unless you added them.

2 Likes

Hi Kevin,

So, now that it seems like I have a handle on the original problem, I’d just like to bump the error I was getting on starting up a project in Designer flagging a ‘collision in system.util.initialize’ Seems like this is a separate, independent issue. Any idea what could be causing it?

Also, I tried creating a gateway event in a project with no inheritors, and do not see it run, even when the gateway timer event is enabled. What could be preventing execution?

As for gateway behavior on ‘global’, it’s entirely possible I misapprehended the workflow. From what I recall, every project had access to the gateway events and shared libraries in designer. Indeed, I’m not aware of a way to affect gateway events in designer other than opening a specific project. Though I could configure those events and libraries from any project in designer, the changes, since they were tied to the gateway, propagated across all projects. They ran once and only once, regardless of how many projects I had open.

It sounds like you’re telling me there was a global project in 7.9 that I was somehow unaware of? Is that the case? I don’t recall one.

If it's marked as 'Inheritable' it will not execute gateway events, among other things. Even if there aren't currently any projects inheriting it.

It was more of an implicit thing in 7.9. Anything that had a global scope (shared script libraries, for example), resided in an internal global project. This project became explicit in 8.0 with the new project system.

There's a blurb in the upgrade guide about how 7.9 -> 8.0 upgrade affects the project system: Ignition 8 Upgrade Guide - Ignition User Manual 8.0 - Ignition Documentation

Oh, and we’re tracking the “system.util.initialize” thing already. It’s low priority and shouldn’t really affect you. It’s not something you’ve caused.

It's a (minor, inconsequential) programming error on our part - nothing you've done, and nothing that'll affect you.

That's really not how it worked in 7.9. Any 'gateway event script' that you made in 7.9 would run exactly once...per project. If you make two gateway startup scripts, in two separate projects...you're going to end up with two scripts running on gateway startup. The same principle applies in 8.0, there's just now an explicit global project.

The gateway event scripts are gateway scoped, in that they execute on the gateway, but the actual definition is still per-project, and there is no "singleton" nature to them.

Thanks for clearing up the system.util.initialize error.

That’s surprising to me, because that’s not the behavior I got out of our gateway timer. It worked according to my (mistaken) understanding during 7.9, and after the upgrade, it’s behavior changed dramatically. We run several projects on several different terminals, but only one alarming terminal. The alarming project looked at a tag to time its klaxon, the tag was set by a Gateway timer event. Every other project could see the (implicit) global project storing the gateway timer, but our timekeeping was correct. That is, only one computer/project (I’d assumed it was the gateway program on the gateway server) was running the event script and setting/resetting the ‘metronome’ tag.

Can you explain how I lucked into getting that behavior in 7.9 vs 8.0?

Also, how, specifically, do I get back to a situation wherein when I define a gateway event, that event triggers once independent of any projects running or not. Is that possible? I much preferred maintaining our code in one shared codebase, and having a super-project capable of executing events without regard for the current status of clients. It allowed me to centralize non-standard behaviors for components and prevented needless duplication of effort in writing and maintaining code across multiple projects. It also helped other users understand what was going on in a project.

I really don’t like that I now have several dozen lines of identical code in two identical components in two windows in the same project, to get behavior that USED to be ‘standard trigger property bound to metronome tag’, with the metronome tag named in such a way as to point the user to the shared library and global events.

It really sounds like you're conflating the idea of a project running with a client being open. They are totally independent. Non-inheritable projects are always running their gateway scoped things. This was true of projects in 7.9 as well.

Define common script library code in 'global'. Make a non-inheritable child project to define your gateway event scripts in. You can reference the script library from 'global' all you want. This project will be running and executing its gateway-scoped event scripts regardless of whether any clients are open or not.

I was indeed my understanding that nothing a project was set up to do (in the local scope) would happen unless a client had the project open or a designer had it in play mode, and that the project had no effect outwards on the global scope, without an explicit call to do so. A call which would not have executed if the project were not active in a client or designer.

All projects I have are currently child projects that inherit ‘global’.

It sounds like I want an inheritable project in which I define a timer event. And a project to inherit that other project, that does nothing, no windows, not client accessible, but as an inheritor will automatically call the timed event. Correct?

I’m going to steer clear of doing anything with ‘global’, as it is currently set to be inherited by all projects. I’d prefer to offload functionality from ‘global’ into other inheritable function(s), until I’m left with a stable system. And then work on understanding how to utilize 'global’s inheritance by my client-facing projects.

Nope.
Gateway scoped things (tags, SFCs, alarm pipelines, transaction groups, gateway event scripts, scheduled reports, webdev resources, etc) are always executing[1]. Only resources specifically highlighted as belonging to the "client" (ie, client event scripts, or naturally any Vision windows or templates) are running on that local client.

[1] when applicable - this is where things get a bit more complicated with the inheritance model in 8.0, but basically the only complication is that "runnable" resources (transaction groups, scheduled reports, gateway event scripts) will not execute if their defining project is marked as 'inheritable' - but, any non-inheritable child project will run (a copy of) those resources.

Another very important distinction, or thing to be aware of: in 7.9, there is an actual, unique, special, "global" project. When you upgrade to 8.0, we make a new project and call it "global" and set up the inheritance tree for you - but there's nothing "special" about that project, anymore (other than it being marked inheritable automatically). You can make your own inheritable "parent" or "whatever" or "mycorp" project and have it act the same way, unlike 7.9, where you were stuck to the somewhat arbitrary set of resources we called "global" or allowed you to put into the 'shared' section.