Non-responsive UI thread detected. Stack saved at ... But I couldn't find where exactly

Hello,

I have developped a vision application that visualises production data using multiple named queries. The application works so fine, except that sometimes it freezes (not responding) for a couple of seconds.

In the diagnostic I found this entry many times : "Non-responsive UI thread detected. Stack saved at ..."

When I open the stack, I couldn't really identify where the issue exactly is .. if anyone can help.

Attached is an example of the saved stack.

NonResponsiveEdt-2026-06-19_100328.json (50.0 KB)

The very first thread in that dump is running a named query from a custom component method (updateDailyTrefilage). Which is running from a property change event. That event runs in the foreground thread, and any delays will freeze the UI.

Run your named queries from named query bindings.

If you absolutely have to use scripts, learn to use system.util.invokeAsynchronous safely.

Thank you @pturmel for your valuable hint.

In fact I have built my whole application on running multiple named queries on a script fired upon a property change .. which makes sense to the unresponsive UI thread issue I have.

The problem now is that I am doing further complex calculation (production KPIs, ratios ...) in my script upon the queries results ... which will be difficult to do on binding directly ... I guess now I have to review the whole building of my project.

Scripts are automatically invoked on the EDT for thread safety when interacting with Swing, but you can always do your own heavyweight processing in an asynchronous thread and move back to the EDT yourself. That's the entire raison d'etre of the system.util.invokeAsynchronous function Phil mentioned.

Basically:

  1. On EDT, user triggers your script by some action
  2. On EDT, script gathers whatever state it needs from the GUI, including enough information to 'call back' when the computation is done
  3. Script passes that state in as arguments to a dedicated function (ideally in your project library) that will run asynchronously
  4. Once the script logic is complete (or at various checkpoints to report progress) script uses system.util.invokeLater to push callbacks on to the EDT.

Deep discussion here:

Yes, old but still applicable.

Thank you @pturmel and @paul-griffith for your support and help.

I'd be honest to say that I was suspecting my need for an asynchronous call method, but I am not used to multithreading in general (and in ignition in particular) so it is kind of a big topic to me.

My problem was solved by simply using an system.util.invokeAsynchronous .. literally this little change made my application works without problem .. Even more, my application is now running more smoothly as the updates are taking place gradually as the script executes (not like before where the screen was freezed until all components are updated at once).

For the record, and to help further users who will stumble across the same problem, I made a short comparison diagram :

PS. This diagram may contain mistakes but it is just to make up my mind :slight_smile:

The diagram is BROKEN. You cannot update the UI components from that background thread. It may appear to work, but will intermittently crash your Vision client. Go back and re-read the old topic I linked. And property access (read or write) or method calls on components must occur on the UI thread. Use invokeLater to fire off such actions.

Refactor your custom methods for "heavyweight calculations" to the script library, and then you can call them as needed from whatever function was invoked asynchronously. Any swing component property values that are needed for the calculation must be packaged up and delivered to the asynchronous function as arguments via the invokeAsynchronous call. Use a nested callback function that can supply the return values to the EDT via invokeLater. It is safe to deliver a swing component as an argument to an asynchronous function and pass it around, and this is sometimes necessary for getting return values to the desired place, but do not touch any of the component's properties or methods outside of a callback function that is called using invokeLater.