How things work - can loaded gateway miss signals from "FAST" tag group?

Hi all
My last question today trying to improve my understanding of ignition and OPC.
Lets assume gateway is running some gateway event scripts which are rare but time consuming. Is it possible that when ignition gateway is executing this event script it might miss some OPC UA or OPC DA signals which were very short. I assume that tags reading these signals were properly configured and placed into “fast” tag group (lets assume 10ms). Can load on the gateway impact the reading from this fast tag group which would not be refreshed as quick as it was supposed to? Trying to broaden the question are any good practices worth mentioning or things to avoid in configuring gateway and OPC in case when reading fast signals is required? thanks for any thoughts!

How are you observing that you’ve missed them? Were you expecting a change event to execute or something else?

It’s always a good idea to look at the missedEvents flag to see if you’re missing tag change events because of too many events or too slow execution.

But that aside… it generally won’t affect your chances receiving a change from an OPC connection.

What is the underlying source of the signal? What server/drivers? If it’s polling-based you’re already operating on hopes and prayers that the poll happens to see it.


I want to expand on this a bit.

You don’t miss changes from an OPC subscription.

But if the you’re using a polling-based driver running in our server, all in the same gateway, and the gateway is experiencing high load (cpu usage, excessive GC), what you will likely experience is that 10ms polling will no longer be consistently 10ms. If it ever even was, which isn’t likely.


To ensure receipt, you need a handshake. Full stop.

To avoid handshake overrun, you must communicate faster than the events can happen, or if queuing, faster than the maximum burst the queue can hold and can encounter.

To avoid races in fast handshakes, you must avoid writing any given variable from two directions. (Never have a PLC reset a bit that Ignition sets, or vice versa.)


thanks for detailed answer. The system is receiving fast signals from the old PLC which controls conveyor. Its super old system nearly falling apart :slight_smile: I don’t know all the details as its my colleague part of the project.

thanks for sharing the knowledge. Any chance you provide an example of the handshake ? I know there are many ways. I can imagine for critical systems we might want to echo the data back so the sender can verify that’s its been sent properly but obviously it makes it slower.

Even if gateway is not overloaded the network might be a bottleneck and have congestions which slows down the traffic. So my example of 10ms cycle is only the wish which might not be fulfilled. My understanding is that Ignition being great product is not real time control system as its sits on unknown customer hardware which is completely different to PLC with its custom kernel operating system and custom hardware. Is there any easy way to monitor the cycle time of the tags and get some alarm when they are updating significantly slower then expected?

To avoid races in fast handshakes, you must avoid writing any given variable from two directions. (Never have a PLC reset a bit that Ignition sets, or vice versa.)

Would using FIFO structure be ideal tool to decouple 2 systems which have different cycle times ie. when one system wants to read it will read from FIFO and the other system do the same. Does it sound right?

My preferred handshake for such tasks is an incrementing integer trigger, that the receiving side echoes via another tag when the transfer is complete. The source can proceed to the next element when the trigger and echo are equal. (I typically make the trigger skip zero to avoid startup errors.)

Yes, precisely. That would be the typical form of “queuing” I referenced.

1 Like

I’m interested in this concept, but am looking for a bit more clarity to help me understand! It sounds like you have two integer tags - each counting up. One counts up when the write is sent and the next counts up once the transfer is complete. Then the tag can be written to again once the two ints match. Is that correct?

What happens if the transfer does not complete (drop in the network for example) and the ints are then no longer matching? Is there a recovery mode for this scenario - to reset both bits such that they match and start the sequence again?

No, just the first. The other is truly an echo.

All other data that needs to change for whatever is collected needs to change before the trigger is incremented again. While the trigger and echo are different, the PLC changes nothing.

For stuff that’s happening really fast, just use a timer event that is faster than the OPC subscription. Self correcting. If using a tag change event, also use a slow timer event for recovery.

1 Like

I am intrigued and would like to understand it well please. To recover shall we use timer event faster or rather slower than OPC subscription? I assume we use OPC for communication. What signals would you consider as fast? - 10ms ? what sort of setting would you use for the timer then - 1s?

I would consider anything needing attention (recording event, etc) faster than ~500ms to be too fast to use a tag change event. Use a timer that is somewhat faster (yes, faster) than the OPC subscription pace for the trigger. That subscription pace should be about twice as fast as the fastest handshaking pace. That event would delegate to a script module function that looks something like this:

# "constants"
triggerPath = '[default]some/path/to/a/fast/integer/trigger'
echoPath = '[default]some/path/to/an/integer/echo'

opcServer = 'Ignition OPC UA Server'
opcItems = [... some list of item values to get when triggered ...]

# Columns in the insert must be the same order as the OPC items.
insertSQL = """Insert Into someTable (... columns ...)
Values (?, ?, .... , ?)"""

def fastHandshake(event):
    trig, echo = [qv.value for qv in system.tag.readBlocking([triggerPath, echoPath])]
    # No action if trig is zero or either is None (bad quality)
    if trig and trig != echo:
        qvList = system.opc.readValues(opcServer, opcItems)
        if all([qv.quality.good for qv in qvList]):
            inserted = system.db.runPrepUpdate(insertSQL, [qv.value for qv in qvList], 'someDatasource')
            if inserted:
                system.tag.writeBlocking([echoPath], [trig])

The above is very similar to what a SQL Bridge transaction group does when in OPC read mode, but has a handshake that doesn’t need an external reset operation.

{ You might want some else clauses to handle unexpected failures more gracefully than repeating the attempts at high speed. }


thank you again for great help!