Message Handler Alternatives & Performance Advice

Hello,

In order to understand my issue, I need to first explain to you my project.

The goal of the project is to collect and display production metrics over time. This needed to be standard for all equipment across the company while being easily deployable and easy to mass-edit. I did this by creating a single Perspective view which would display the data dynamically. The tag names are parameterized via view params, which then point to a UDT instance in my tags. The UDT instance contains approximately 15 tags that have tag change events tied to them, and that drives the collection of the data, for example, when a part is produced, the tag change script executes and records a part back to my sql server. This is a basic example, but there are several of these tag change event scripts to handle different types of data recording and updating.

The tag change event scripts can’t call project scripts directly due to scope issues, so I opted to use several message handlers inside of the project to handle this. This worked well at first, but as the project grew and was deployed to more and more equipment, the tag change event scripts started missing events due to long script execution.

My solution to this was to use a thread handler which my message handlers would hand off the events to, making my message handler scripts execute in sub 1ms times and the longer tasks get queued up in my thread pool. This solved the majority of my missed events issues. However, the project is ever growing and will need to grow still to be 10x the size it currently is, so I am in need of a better performing, more reliable way of doing this. Performance is important, but data accuracy is more important. With it missing events, I could be missing valuable production data.

I already added the below to my ignition.conf:

wrapper.java.additional.3=-Dignition.tags.scriptqueuemaxsize=20
wrapper.java.additional.4=-Dignition.tags.scriptthreads=16

Those java tunables made a big difference, but I wasn’t comfortable going higher than that, maybe I can though? I was hoping someone at inductive could weigh in on that. The gateway stays around 20% cpu usage, spiking to 45% at busy times. Memory is not an issue.

I’m out of ideas on how I can do this while maintaining the super simple deployment method. I have a script set to browse OPC devices for the UDT in the PLC, and when it finds it, it auto creates the ignition tags and then everything just works, no further setup required. This is an important requirement of the project, otherwise I would just use project scoped event scripts, which, as far as I can tell, are incapable of missing events somehow.

Thanks for any help, I’m open to all advice.

Posting some excerpts from a PM so it's available:

It’s probably safe to go a little higher on each of these.

Are you sure you’re missing events and it’s not something else? There’s a missedEvents flag you can check and use to log a warning and verify this is actually your issue.

Both will lead to higher memory usage in their own way. I’d be wary of going much higher on the thread count but you might be able to keep increasing the queue size depending on how many tags have these scripts on them.

It sounds like you’re either generating a tremendous number of events and/or they’re not all executing in 1ms like you think.

Setting the logger for tags.eventscripts.dispatcher to TRACE level will show how long all the script executions are taking and when overflows occur.

https://docs.inductiveautomation.com/display/DOC81/Diagnostics+-+Logs#DiagnosticsLogs-ChangingLoggingLevels

Okay, so doing that provided me with some insight on to what is causing the overflows. I have an OPC tag that is a timer with a scan rate of 1 second that triggers a script that writes the value of the timer tag to a memory tag. The purpose of this is so that I can use an index value in my PLC for which hour of the day to write the data to using a single PLC value. That is kind of confusing so let me explain. I am recording data for each hour throughout a 12 hour shift. In the PLC, I only have data for the current hour, so what I do is I move it into a memory tag every time it changes, so that when the hour changes, the script will write the next hours data to the next hours memory tags and leave the previous hour in place so that it stays on the screen and doesn’t zero out.

This writing to memory tags is what is causing all of my performance issues, there are hundreds, if not thousands of these executing per minute. I’m not exactly sure how I can solve my issue. Is there a better way to make a memory tag dynamically reflect an OPC tag that is more performant?

Reference tag, expression tag, or derived tag?

Not following exactly what’s going on, so not sure if that’s dynamic enough. Do you mean the target memory tag changes based on some criteria? If so then not sure these will help.

Yes the target memory tag changes based on what hour it is. So for example, I have a timer tag, let’s call it timer1. I then have twelve memory tags, time1-12. I then have a tag called currentHour.

I move the value of timer1 into the time1-12 tag that corresponds with the current hour. So if currentHour = 6, I move timer1 into time6.