Hi All,
Im using Ignition 8.1.35 with Vision.
We have made a small search tool to search for events in a special table in SQL Server that gets data from the alarm journal.
We have had some help making the right indexes and searching is generally fast.
From the GUI we call runPrepQuery using the example from the documentation system.util.invokeAsynchronous:
def longProcess(rootContainer = event.source.parent):
import system
# Do something here with the database that takes a long time
results = ...( call runPrepQuery )
# Now we'll send our results back to the UI
def sendBack(results = results, rootContainer = rootContainer):
rootContainer.resultsProperty = results
system.util.invokeLater(sendBack)
system.util.invokeAsynchronous(longProcess)
I have seen some examples of users making queries that run longer than the 1 minute timeout on the Gateway
and the query ends up hanging in the Gateway and I need to cancel the query in the Gateway.
Can you somehow cancel the query before it times out in the Gateway?
I've looked at the transaction parameter (tx) for the runPrepQuery, but that put's a lock on my table and that is it not the way to go.
To my knowledge there is no mechanism for canceling a query from Ignition. The best you can probably do is to catch the timeout exception and then react appropriately.
I'm just starting to realise that the SQL query run in a Gateway scope, and the timeout that the user sees is between the SCADA client
and the Gateway (client scope).
Interestining idea from Benjamin, I'm thinking would it be possible to make a monitor thread, that gets the
time from system.util.getReadTimeout() and a few seconds before the limit is reached it kills the database query thread if there are no result from the database?
That still won't kill the query running in the database. The only way to run really long queries in a Vision client is to start the query in an async thread or thread pool via a gateway message handler, track it with some persistent dictionary, and send the final result back with system.util.sendMessage() from the gateway to target the specific client ID. The initial request would use system.util.sendRequest() and would return a token to use to identify the proper result in the client message handler.
It is doable, but a complicated mess. It is better to redesign your DB so your queries are near-instant. Use precomputed tables and/or materialized views to limit the query work at time of use.
Thanks Phil,
I agree that would be a messy implementation, that my colleagues and me would have to maintain
The table has almost 75 mio. rows I'm not sure that I can make every query that a user can think of run fast.
Another option could be to handle the sql query timeout in a python fastapi webservice, that sends a kill command in sql server
if it takes longer than 1 minute. Ignition could use the system.net.httpget to send queries, but then again I have some external
code that needs to be maintained, and keept up to date.
I think my best option is to set some limits in the userinterface, so that a user cannot query a years data without using an indexed column.
I feel like we have this conversation all over this forum about what users can handle and consume. I do data analytics everyday of my life at work, and 75 million rows is beyond any number I could consume and use. Your users will also not really benefit from that much data all at once.
I agree you should add some limitations. You as the developer in conjunction with your end user need to identify your User Requirements. If the most data they need at once is say 3 months, give them the option for 3-6 months or something of that sort.
If you have a table with millions of rows, make sure its indexed properly, and you may implement a read table and a write table. If you are constantly writing to a huge table and also reading from it that can cause long running queries as well.