Rule Error "null"

I have a rule that is generating the following error in the log. I have checks around any item to see if it might be NULL and do not see any problems despite logging every step in the rule. Any thoughts on how to debug?

2018-09-21 10:13:31.368 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'React on OccupancyControl change/update': null

Probably would help if you posted the rule and items…

Hard to look at the rule out of context of the entire set of rules/items files.

Are rules thread safe? Ie if a rule is fired twice are the variables in the rule separate instances or the same?

They exist in the same thread within the same file.

From my limited testing, it seems the same rule can be running at the same time if there are 2 events that trigger it? Especially using Member of rules. That would imply more than one thread?

Yes it would, 1 Thread for each rule running. If 1 rule is running twice then 2 threads… And so on

Are the variables in each running rule different ie thread safe or not?

Depends on how it’s declared but for the most part no.

is there way other than var / val to declare them to make them thread safe? what about iterators in a foreach loop?

Alternatively, I used a lock as per this thread. That solved the error.

1 Like

Global Val’s can be used with near impunity since you can’t change them. Global vars are not thread safe. Local vars will only exist in the installer if the Rule running so from that perspective they are thread safe in so far as each thread gets it’s own variable.

Be carful work locks. It is really easy to run into troubke with locks since it is possible for errors to occur that prevent finally from being called and your lock never unlocked.

Only Val’s are available to a forEach loop. If you want to create it summarize some data from all the members of the collection you should use a map reduce.

Hard to provide useful concrete help when answering general questions without code and items to look at.

1 Like

What about triggeringItem in a rule? If you are using the “member of” Group trigger and 2 members of that group change at nearly the same time what happens to the triggeringItem in the rule? Does each running version of the rule reference the correct triggeringItem or if the rule fires again does the triggeringItem change the one running in the rule that fired first if that rule is still running?

triggeringItem gets populated only for one rule’s context. So one instance of the rule will run with triggeringItem set to one of the items and another instance with triggeringItem set to the other item.

I’ve not looked in the code to verify this is the case but that is what I’ve observed.

Rick,

Can the code below be optimized? In short, I have an item that is a member of several groups and I want to get one of these groups for further use. The group I want is a member of another group and that is how I identify the group I want…

        var GroupItem area = null
        triggeringItem.getGroupNames.forEach [ i | // iterate over groups the triggering item is a member of 
            val b = gArea.members.findFirst [ a | a.name == i ] as GroupItem // find if the group is a member of gArea
            if (b !== null) {
                area = b // set area when we find the right group
            }
        ]

A lot more reading and trial and error … this seems to work :slight_smile:

val GroupItem area = gArea.members.findFirst [ a | a.name == triggeringItem.getGroupNames.findFirst [ i | a.name == i ] ]

More interesting, is the log error of

2018-09-21 10:13:31.368 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘React on OccupancyControl change/update’: null

Is no longer present in the logger after shortening the above code to a single line. All the other code in the rule is the same. Makes me think that something in the rules DSL is not thread safe?

For the optimizations, often I’ve found the best optimization is a whole other approach (e.g. not using two sets of Groups at all) but it’s impossible to tell without more context.

It’s frustrating when users ask how to do something to solve a particular problem they have the way they have decided it needs to be solved without giving us the opportunity to explore other approaches that may sidestep the root cause of the problem in the first place.

null errors like that usually have something to do with type but it’s hard to say if that it’s there case here.

I can say this is one of the few case where the full collection of set operators would be useful because all you are doing here is taking the intersection of the two Sets.

I can say that the first approach won’t work because you can’t access or assign a var from within a forEach loop. Though I’m pretty sure that you would get asyntax error for that. Did you watch the logs when the .rules file was loaded?

I’m not at a computer so can’t test this out, but I think using something like this would work as well:

val GroupItem area = gArea.members.reduce[ result, area | result = if(triggeringItem.getGroupNames.contains(area.name)) area else result ]

Another error I have seen with this rule in the logger is

2018-09-24 10:58:01.751 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'React on OccupancyState changed': The name 'logInfo' cannot be resolved to an item or type; line 14, column 5, length 106

This seems to only happen on the first time the rule is executed. Otherwise the logging command works.

That is definitely the known startup timing bug. The Rules start executing before everything is ready. There are all sorts of work arounds that people apply like setting a timer and only moving the .rules files over to the rules folder after enough time has passed for everything else to be loaded and the like.

I try to avoid relying too much on System started Rules until this bug gets fixed.

These errors happen at systemstartup and also when editing and saving - ie on first load after changing the rule.

In addition, it seems the use group iterators are not thread safe. The only way to get completely rids of these errors was using locks in the rule.