RefreshBinding after a delay

Hi,

I was wondering if it's possible to trigger a RefreshBinding after a delay in a component.

For example, this a one shot button:

from threading import Timer
	
	InsertData()
	
	def runThisLater(param):
		system.perspective.sendMessage("Table Refresh Data", payload = {}, scope = "page")
	
	Timer(2.0, runThisLater, ["Stop Waiting, I'm done"]).start()
	
	self.props.value = 0

So, InsertData() will add some entries to a database and after that's done I would like to refresh the named query binding on a table.

The message handler script just have one line:

self.refreshBinding("props.data")

If a run a SendMessage outside a delay it would refresh, but not inside.

What could trigger a RefreshBinding after "whatever is being done with the database" is completed?

I fail to see the need for a delay here. If you write your code in a blocking manner, then you can simply refresh the binding after the insert data function; otherwise, how would you know how long to wait before you refresh the binding?

InsertData()
self.getSibling("Table").refreshBinding("props.data")
4 Likes

This.

And ditch all use of Timer (or any purely python infrastructure--use java instead).

From my tests, it doesn't update to the new values right away.

Another example would be:

  1. Insert data in a table.
  2. Read inserted data.
  3. Result: Old data or an error if the table was empty.

So, it does take a couple of milliseconds to get to the database.

That's a good point. If the database is down then I'll just read old data in the case of inserting entries and in the case of showing data with a RefreshBinding nothing will be shown.

The function system.util.invokeLater(function, [delay]) can only be used for Vision. Apart from from threading import Timer, I don't see anymore options in the manual.

Gateway Event timers, as far as I know, cannot be controlled using a start/stop function.

While answering this thread I came across with java.util.Timer.scheduleAtFixedRate() from Gateway Event Scripts - Ignition User Manual 8.1 - Ignition Documentation
Are you referring to those functions?

What Phil meant is that you can import Java into Jython, which means you can use

from java.util import Timer

instead of the python version.
And he suggests you do.

If you absolutely must. The correct answer is to arrange your code and the operations it performs so that all waiting is naturally part of the operations, and therefore no sleeping or timing is required. A scripted DB update followed by a binding refresh fits this pattern. As @dkhayes117 points out above.

Using any form of .sleep() is a "code smell" that suggests you are doing something wrong or architecturally unwise.

You say that the new data is not in place for Select immediately after your Insert operation. That is a DB bug or config error--quite likely poor choice of transaction isolation. Fix that.

Perhaps you should show your code for InsertData().

Sounds good. I wonder why it's not in the manual.

@pturmel
I agree with everything from your last post.
This is the part of the code where I could see that I cannot just insert and right after that read the DB.

def InsertDate():
	
	date = system.date.now()
	
	system.db.runSFPrepUpdate('INSERT INTO time (storetime) VALUES (?)', [date], datasources=["TestDB"])
	
	return None

def InsertData():
	
	InsertDate()
    
    timeID = system.db.runScalarQuery("SELECT max(id) FROM time", "TestDB")
	
	return None

When working on the tables, I also noticed that I cannot just delete and refresh the table in the very next instruction. So, something needs to guarantee that the DB operation is done before moving forward. That's the poor architecture that I have right now.

This is the problem. Don't use the store and forward system for user-interface operations.

Part of the code is inserting with a button and the other part will run automatically on a scheduled basis. I would think that in both scenarios it should not use the store and forward system. Is that correct?

Definitely not for the button. The automatic part might, depending on whether you are handling errors or just want the insert to wait until the DB can accept it.

I think your answer is the solution to the thread but I'll take it a bit further.

I should do some error handling. Writing directly to the database and wishing for the best in the background doesn't seem correct. Making sure that the data is written should be a customized solution or is there a standard way that I should look at?

Catching errors with database calls generally requires explicitly capturing java exceptions in an except: clause separate from jython errors. Start here:

https://forum.inductiveautomation.com/search?q=except%20Throwable%20%40pturmel%20order%3Alatest

Because it's a Jython thing, not specific to ignition.