[8.1.3] Designer freezes and becomes unresponsive

Hello there, time for my daily problem thread !

So I’m replacing an outdated bag of worms that was supposed to mimic the behavior of an accordion, with the built-in accordion component.

I’m generating the items with a script, because it’s a quite complex accordion:

  • Header is a view, with a flex repeater in it
  • Body also has a flex repeater, instances depend on data from the header
  • Each instance in the body’s flex repeater needs to compute a value
  • The header needs to show an aggregation of those computed values
  • There are bindings on quite a few things in those views

It actually works quite well in a browser, but when I try opening the view containing the accordion in designer, it freezes, with the occasional sign of life, but it’s functionally dead. I’ve seen it reach 100% CPU usage for a solid minute, probably more, and even crash after running out of memory.
Now, the problems stop if I disable some of the bindings (in the view that is repeated in each body), which allows me to open the component, work on it, then close it and re-enable the bindings, but that’s not an ideal solution…

Here’s how I do it, in case (and in the hope that) someone catches something that could be done in a better way.
The items property is bound to a query.
The returned json is then sent through this script transform:

row_list = []
for entry in value:
	tcu_params = system.dataset.toPyDataSet(
		system.db.runNamedQuery("Tcu/Details", {
			'row': entry['row'],
			'zone': entry['zone_num']
		})
	)
	body_params = []
	total_alarms = 0
	for tcu in tcu_params:
		alarms = len(system.alarm.queryStatus(path="*" + tcu[1] + "*", state=["activeAcked"]))
		total_alarms += alarms
		body_params.append({
			'position': tcu[0],
			'tcu_name': tcu[1],
			'tcu_num_row': tcu[2],
			'tcu_num_col': tcu[3],
			'tcu_id': tcu[4],
			'failures': alarms
		})

	header_params = {
		'failures': total_fails,
		'row': entry['row'],
		'zone': entry['zone_num']
	}

	row_list.append({
		'expanded': False,
		'header': {
			'toggle': {
				'enabled': True,
				'expandedIcon': {
					'path': "material/keyboard_arrow_down"
				},
				'collapsedIcon': {
					'path': "material/keyboard_arrow_right"
				}
			},
			'content': {
				'type': "view",
				'useDefaultViewWidth': False,
				'useDefaultViewHeight': False,
				'viewPath': header_view_path,
				'viewParams': header_params
			},
			'height': "30px",
			'style': {
				'color': "#808080",
				'backgroundColor': "#E4EAF0"
			}
		},
		'body': {
			'viewPath': body_view_path,
			'viewParams': {'instances_data': body_params},
			'useDefaultViewHeight': False,
			'useDefaultViewWidth': False,
			'height': "auto",
			'style': {
				'margin': 0,
				'padding-top': 5,
				'padding-bottom': 5
			}
		}
	})

return row_list

I’m particularly interested in improving the alarm counting thing, which I copy-pasted from the previous version of the component, which was made by someone else. I’m quite new to ignition and I haven’t figured out that queryStatus function just yet.
I’m open to any suggestion, even and especially if you can think of a better approach to the whole thing, maybe binding the body’s view flex repeater instances separately (which is imo better design, but also makes a few things difficult). Any help I can get !

edit: A screenshot might help clear things up:
image

What igntion version?

8.1.3, I’ll add that to the first post.

8.1.0/2/3 all have a performance bug in the designer. Try testing in 8.1.4 and see if it’s any faster. We were on 8.1.3 and designer performance was a killer! It’s better in 8.1.4, but still not even close to Vision performance… There’s always hope

Alright, thanks Nick.
I’ll try updating to 1.4 then

Hi @pascal.fragnoud, the following suggestion(s) might not resolve the root cause of your issue but could help.

Could the query below be removed by using a JOIN in the items binding query to get the same data? This could reduce the number of DB calls required significantly depending on the size of your original dataset.

system.db.runNamedQuery("Tcu/Details", {
			'row': entry['row'],
			'zone': entry['zone_num']
		}

I haven’t figured out that queryStatus function just yet

This is finding all alarm instances with the 'tcu_name' (e.g. Alarm1 where * is a wildcard) in the alarm path that are still active but acknowledged. For more info see here.

Now, the problems stop if I disable some of the bindings (in the view that is repeated in each body)

Do you have examples of these?

I’m open to any suggestion, even and especially if you can think of a better approach to the whole thing

Looking at it another way you could look at using a flex repeater design that emulates the accordion functionality. Using this you could get the data required for the specific view on-the-fly when the specific instance is expanded. I'm sure I've done something like this already :thinking:, I can dig it out if you would find it useful? But I'm guessing this is what you were originally trying to get away from :sweat_smile:

Hello Matthew, thanks a lot for your time and input !

I’m… terrible at SQL :stuck_out_tongue:
I’m learning it on the job, I come from a system oriented background - I can code anything in C, but SQL is preeeetty far from my confort zone !

Maybe I could get all the data from one query, this is actually a very good idea, I’ll try my best at working this out tomorrow.

I’ve read the queryStatus doc page, but I’m not familiar with some of the terms used there, so I’ll need to take some time to figure it out. It’s definitely on my todo list, but it’s sadly not my highest priority right now, so I just used what was already there and seemed to work.

As for the bindings, if you look at the screenshot i posted, you’ll see rows with 2 rectangles and a lock.
Those 3 things have properties bound to tags related to each TCU, to show their states.
Here’s a screenshot so you can see what they look like:


Between those 3 elements, there’s a total of 4 bindings, all bound to a specific tag that monitors a particular state of the TCU. They’re then mapped to classes, icons, etc.
There are 42 rows, for a total of about 150 TCUs.

Considering the flex repeater solution… I actually implemented one, and ran into the same deadlock/freeze problems. Which is when I realized there was a built-in component for this, so I tried it out. It happens to load a tiny bit faster than my previous solution in browser, but runs into pretty much the same issue in the designer…
Though I might actually switch back to a custom made accordion with flex repeaters, to get more control over things. This might allow me to lazily evaluate the body views when needed.
I had this exact workaround in mind, but I wanted to try to bind it to the ‘expanded’ property of each item in the accordion. This turned out to be a real head-scratcher…

Another thing to consider: The number of rows and the associated TCUs will NOT change. So I can get rid of the original query now that the datastructure has been generated, to try and untangle this clusterfu** a little bit. I will still need to update the TCUs statuses though.

Anyway, thanks again, I’ll have a go at it tomorrow, for now it’s time to go home and get some dinner.
Have a good day/evening (or night in the case of nminchin) !

Doing this in a transform is a terrible idea (particularly with those wildcards).
Query your alarm counts in a gateway timer script, cache them in a tag (maybe construct a dataset that's already got a column per tcu[1]?), then look up the appropriate value to use in this transform.

3 Likes

I know this pain all to well :smiley: a few years down the line I'm now capable (but by no means an expert). If you get stuck and it's MSSQL I may be able to help.

Unfortunately there's not a way to dynamically create bindings in the runtime (as far as I'm aware). Checking the expanded prop for each item could be done via scripting, but it would be a lot of work and would probably have it's own performance implications.

It looks like @PGriffith has most likely got to the root of the issue. I've not had the need to use the queryStatus function yet, so thank you for the heads up :+1:. I probably would have fallen in the same trap at some point :laughing:

It was far too late when I replied to see the queryStatus function being called, but this can't be emphasised enough. Never call queryStatus from the GUI. If it doesn't kill your client, it will kill your gateway

3 Likes

Alright, I guess it’s time to read about that function and do some testing.
Problem is, it seems it can’t be used in the script console, which makes it hard to test its behavior…
I guess I’ll whip out the browser console then !

Thanks for the help folks, I might come back later with more problems :wink:

If this can’t be emphasized enough, then why do you not make that statement in the user manual? Additionally, the very first scripting example in the manual is a button that puts queryStatus data in a table in the UI. Am I missing a PSA somewhere on the dangers of using that function in the UI? If so please point me to it. Just saying that you guys sound really condescending here when you say stuff like that, as if we should all know as much as you do. What you think is common sense is not necessarily common for us non-devs and new Ignition users. As excellent as you all can be in this support game, you occasionally forget how to deliver good info in a respectful manner. :slight_smile: Making your customers feel dumb is a “terrible idea”

1 Like

@nminchin is not an IA employee.

1 Like

Come on, you’re over dramatizing this. So I had a terrible idea, big deal… It’s not the first one and certainly not the last. I don’t feel anyone was disrespectful here.

He’s just an over-worked non-IA employee who sometimes replies after a long day, and perhaps, sometimes says things a little too bluntly and with too much sass :roll_eyes: noted though

2 Likes

Your prerogative on how to feel about it, but there is no good customer service manager that wants to see their people talk to customers like that. Don’t get me wrong, I’m a huge fan of IA and I push this platform everywhere I can. I’m not thin-skinned, I actually just care about how people that I send over here get spoken to when they are putting themselves out there in a forum. Pretty classic etiquette issue IMO. Didn’t mean to hijack the thread, but if my team were to talk to our customers like that they would be getting some training to correct it.

1 Like

Got it, but others are…

It’s getting a little spicy in this thread.

Not to derail things, but yeah you’re right in that the first example on the queryStatus page does suggest calling the function from a component-based script, which given the conversation here does seem problematic. My apologies for that, as I wasn’t aware of the example until recently.

I wanted to make some improvements, so I did the following:

  • Left the first example since it’s simplistic and shows just basic usage of the function, but added a comment suggesting that it’s not the ideal approach for component based scripts.
  • Added a new example (right after the first) that demonstrates a way to call queryStatus that should be less impactful on performance when called from the GUI, which makes use of system.util.invokeAsynchronous and system.util.invokeLater. It’s fairly verbose with all the comments, but it’s kinda tricky since we’re making use of a couple of different functions and concepts within the same example.
  • Added a note towards the top of the page suggesting that the function can be used in a gateway timer script to pass some information, such as an alarm count, to a tag. Similar to what @PGriffith said earlier.

I know this is just a bandage for a larger issue, but hopefully it’s a step in the right direction. Y’all let me know if you have any further suggestions.

7 Likes

Awesome, thanks Paul. Didn’t mean to raise the temp in the thread, I just want IA to (continue to) be the best in the game…

1 Like

Hello Paul,

How about system.tag.readBlocking() ?
Can I call that in a binding on my embedded views that get repeated in a flex repeater to get the dataset generated from a queryStatus call in gateway event timer script ?
I’m trying to figure out the best way to fill my accordion and keep it up to date - Only one thing needs to be updated from that dataset, and I’m wondering if it’s better to do it all in the items binding of the accordion and send the data to each instance through params, or let the instances do that call individually.

Have a good day !