Tag write slower from gateway tag event than from Vision trigger

I have a script that updates about 1500 PLC tags and then runs some internal scripts after the update is complete. The main script uses a system.tag.writeAsync call to update all the tags at once and then call a secondary script that triggers the internal scripts. The secondary scripts use 3 system.tag.writeBlocking calls to write 3 values to the PLC. All of this is triggered from a Vision window and has been working great for 6 months.

Recently, I had to make a change that would allow this same script to be run from a gateway event tag change script. The function will work but the tag writes are much SLOWER. When triggered from the Vision window, the 1500 tag writes take less than 1s. When triggered from the gateway tag event, the same tag writes will sometimes go quickly but may also timeout at 45s. Other times the 1500 tags will write quickly and then the subsequent writeBlocking calls will be slow.

Why is this? Is there a better way to handle this? I am hesitant to post any of my code because of the sensitive nature of the project I am working on. If required, I can post a modified version.

Thanks in advance,
Dan

You may want to have IA support look at this--they can work under a suitable NDA.

But first, check if you are batching your writes with lists with system.tag.writeBlocking().

Thanks for the quick reply. The large write occurs with a single call and a list of around 1500 tags. There are then three additional writes that each write to a single tag. When this is called from a Vision window, the entire thing works smoothly. When called from a gateway tag change event, it is consistently slower to the point of running into the default 45s timeout. When I watch the tags, sometimes the bottleneck is in the large write and sometimes it makes it through that write quickly and gets hung up on a writeBlocking call that is sent to a single tag.

What version of Ignition is this?

8.1.25

Set loggers Tags.Opc.Writes and tags.execution.batchoperations to DEBUG level and next time it's slow grab the logs and upload them.

Also - what 45 second timeout are you talking about? What call times out from that?

edit: must be on the subsequent writeBlocking calls.

The loggers I mentioned will confirm this, but I'm pretty sure I can explain what's happening.

Writes to OPC tags batched on a per-server basis. Only one batch per server is allowed to be executing at any given time.

When you execute all of this from Vision, for whatever reasons, I'm guessing these writes all end up in the same batch.

When you execute from a tag change script, I'm guessing you end up with one batch executing the 1500 writes, and a second batch for the 3 tags waiting on that first batch. Writing to 1500 tags is likely much slower than you realize because you've been hiding it using writeAsync.

We're planning some changes to the batching to allow some amount of parallelism, though I can't say for sure it will help in this case or not. In the meantime you could switch to system.opc.write* for either the 1500 tags, or the subsequent 3 tags, or both.

Thanks. I will see what the effect is of switching to system.opc.write.

I moved the scripts to use system.opc.writeValues and it seems to be working.

Though, I'm having a hard time accepting your explanation.

I was using system.tag.writeAsync. I thought that this function issued the tag writes and then when that function is complete, it will issue a call to the callback function. I was originally using an invokelater call to execute the secondary scripts after the large tag write. This invokelater was waiting 5s for the writes to complete and be read back into the tag provider. However, invokelater does not work from the gateway so I put in an expression tag that sees when the update occurs and sets a expression tag to True 5s later. The secondary scripts now run from a tag change script.

EDIT: I guess what I am having a hard time understanding is this. Doesn't system.tag.writeAsync complete its write before calling the callback function? Shouldn't that block of tag writes be complete by the time it is getting to the 3 tag writes in the callback function?

You should have provided more information.

The loggers I mentioned will still be useful in determining what is happening, should you revert to the original setup that doesn't use system.opc.write.

Yes, but you didn't mention using the callback at any point...

I thought system.tag.writeAsync HAS to have a callback function.

Nope, optional, and often ignored by people... unfortunately.

So FWIW, when you write this logic in the gateway inside the callback from writeAsync, there's simply no need for invokeLater. I'm not sure there was when it was in the client, either, unless you were also manipulating the UI in some manner.

Below is a summary of the code...

get tag values to write
write a 1 into status tag
call system.tag.writeAsync with callback function

callback function
write a 2 into status tag
write a 1 into plc update bit (this causes plc to move parameters into internal PLC tags)
write a 3 into status tag

expression tags
tag 1: True if status tag = 3 and has been for more than 5s
on value change. if value==1, call secondary function

When called from Vision or Script Console, this works great. When called from the gateway, sometimes I would see the status tag get stuck at 1 for 45s, sometimes 2. Sometimes, it would work smoothly but usually not

The invokelater was because the secondary scripts were updating internal tags based on plc values. However, the parameter update would cause the plc value changes and the OPC server needed time to both write the parameter values and read the updated values. In testing, I found 5 seconds was more than enough time for this to happen. I used invokeLater instead of pause because pause would lock up the entire UI

I have to step out for a while to take my son to a baseball lesson. I really appreciate how quickly your responses have come and how informed they are. I will try to pick this thread back up (maybe Monday) to try to get to the bottom of the issue

I wanted to bump this thread. It seems like it was left unanswered after the realization that I was using a callback function.

The reason that the callback function was using an invokeLater is that the tag writes were writing to one set of PLC tags. After this large (1500 tags) write is successful, an update in the PLC is toggled. This triggers a series of logic that moves the parameter values into another set of PLC tags that control how the machine operates.

Based on the value of these internal PLC tags, Ignition will adjust its UI so that it displays correctly for the loaded machine type. Ignition has to wait for the OPC server to read these new tag values before it can run several scripts that are needed to adjust the UI. The invokeLater calls were timed so that these scripts would wait a few seconds for the OPC server to read the new tag values before calling these UI update scripts. Since invokeLater does not seem to work when called by a gateway tag change event, I created a internal expression tags that trigger after the parameters are loaded.

I have this whole thing working by switching away from system.tag.writeAsync and system.tag.writeBlocking. I am currently using system.opc.writeValues.

I would still like to know why the tag writes are timing out when coming triggered by a gateway tag change event. The writeBlocking that is called by the callback function should not be waiting on the initial tag write to finish.

Those loggers I mentioned would still be the starting point. Even if it’s not the large write you invoke right before there could still be some other writes going on causing them to queue. You may end up needing to work with support to accommodate the back and forth of logger changes and log files.