Any way to synchronize (single thread) a rule?

Hello community...

I have a rule that is triggered by multiple events. Within the actions of the rule, I have a repeat loop. With the new Scheduled Jobs logging feature, I have discovered that this rule always has two repeat loops executing. It should only have one. I believe it is getting triggered twice by two different events at the same time and thus, creating two repeat loops.

Is there a way I can single thread and/or synchronize this action to ensure only one repeat loop is created? I originally had a rule variable to designate whether it was repeating and I checked it before going into the repeat section, but that did not solve it. I believe it did not solve it because they were running in parallel and I had a race condition that the variable had the same value at the same time between the two triggered thread executions.

I am wondering if the new Wait action can be useful here, but struggling to think how to use it for this situation.

Thank You
Troy

Try this:

Put in a Required Expression of Private Boolean true. As first action, set Private Boolean to false, and as last action set it to true again.

3 Likes

Thanks @bravenel

I rebuilt this rule on Rule-5.1 in order to take advantage of Required Expression, but I don't think this will achieve the desired behavior. Since the internal Repeat loop is running, the actions don't end and the Private Boolean does not get set back to true. Hence, when the next trigger is called, the expression is false and the action to Stop Repeating Actions doesn't get called and the Repeat loop runs forever.

At first I thought maybe I could set Private Boolean back to true in the Repeat Loop, but that seems problematic as well. Like the race conditions of the Repeat scheduler running just as events are triggered, or as the actions are currently executing for a new event.

I also wondered what happens with event triggers for rules when Required Expressions are false. Is the event lost for that trigger, or queued for as soon as the Required Expression is true?

Hmm. Still pondering a solution.

Maybe I need to move the repeating actions to their own rule, that triggers every n mins. Then this rule, just pauses or resumes that "repeat" rule. Should be no harm in resuming a rule multiple times in parallel. But seems overly complicated to need to do that.

Generally speaking, it removes the trigger subscriptions when the Required Expression becomes false, so that it is not triggered at all. Even if triggered, it won't run if the Required Expression is false. But, this does only apply to trigger events, not things scheduled within the rule.

Clearly, you need to figure something out. You have a complicated rule, with embedded repeats within conditionals and multiple triggers. Something is bound not to work right with that combination. Time to 'refactor' your logic for this. Follow KISS for best outcome.

1 Like

I would suggest that you look at using Repeat While Expression or Repeat Until Expression, so that you don't need to stop the repetition from a triggered event. It can just check those conditions on each loop, and stop when done on its own.

Ive also solved a synchronous call problem by putting in a variable delay, and then doing the boolean flag so the one that is delayed longer is the one locked out

Well I believe I solved my root issue by splitting the logic into two different rules. One rule to determine the logic of whether a loop should run or not, then another rule that just contains the loop logic with a trigger for every n minutes.

Rule to determine if loop should run:

Rule with loop logic:
image

I wish I didn't have to solve it with an extra creation of rules. I like to keep my rules self-contained for all the logic related to that specific automation, versus split across multiple rules. Just keeps it a little more self-documenting, since it is not obvious that multiple rules need to work together to complete an automation.

@cgmckeever - That's an interesting idea of introducing random delay timing into multiple thread rule executions and allowing the boolean flag to become effective. I'll keep that idea in my bag of tricks. Thanks.

@bravenel - I don't think the other forms of repeats will solve the root problem. The root problem was if there are multiple threads running the same rule, it could schedule multiple Repeats. At the worst, that can be problematic depending on what the Repeat is executing. At the least, those multiple Repeats are taking up unnecessary computing resources. This seems like it could be a general problem for using Repeats in rule actions all together.

That isn't really the root problem at all, but rather what it is structurally that causes multiple instances. You use triggers to communicate state changes to the rule, when the rule could examine those states on its own. Also, you use *changed* in your triggers instead of specific states, which cause over-triggering and the need to examine the state with conditionals, and the over-triggering leads to multiple instances. Using *changed* just throws good information away.

You don't even need a repeat at all for what you're trying to accomplish, which is to automate a fan based on temperature with some additional factors. Your repeat is effectively a 'poll' of state. In an event driven system you don't need to poll anything. Instead, you design the automation to be driven by the state change events.

These rules are inside out, and that is why you have the complexity.

Could you state in English what you are trying to accomplish? Since the core of your automation is setting the fan speed based on temperature, have you considered using the temperature as the specific trigger? This is effectively a fan thermostat, and thermostats are driven by temperature events, not by polling.

Sometimes multiple rules are the best way to solve certain problems, although in this case what you have is still a convoluted solution with one rule pausing another. Your automation may require 3 rules, each very simple, to do what you're trying to accomplish. One would be triggered by Temperature < 50, one by Temperature > 85, and the third dealing with turning the fan off. In each rule, the Required Expression would deal with all of the conditions that apply to setting the fan to high, medium or off. There would be no repeats, no conditional actions at all, and no rule calling another. Use comments or notes, as well a rule names to show that these 3 rules control the Game Room Ceiling Fan.

A little background on why I use the Repeats for polling the states would be useful here...

In the past, I have found if I trigger on temperature events from sensors, outside weather events, or distance in miles from home in presence, these became very chatty. It ended up triggering these types of rules a LOT. This appeared to cause performance and DB concerns on the platform. When I had that approach before, I was getting regular messages about DB growth, runtime stats calling out those rules as anomalies, repeated commands sent to devices that were not needed and the platform in general was visibly slower. Once I switched to polling in Repeats for those types of states, things became much more stable, because I could essentially control the frequency.

The reason I am interested in changed and not just a single binary, is because I use the single rule to control both binary states.

Yes, I can use multiple rules to accomplish automation tasks for the same device. Just seemed confusing and wasteful to me. But will keep that in mind.

You can avoid this in the schema I proposed above by adding to the Predicate Expression that the fan is not already in the target state. For example, in a rule to turn on above 85, if the fan is already on high, it would not be triggered at all (when Predicate Expression is false, subscriptions to the triggers are removed). The Predicate Expression would not be over evaluated, as it would not change even as frequently as your triggers do now. The temperature could report every minute but nothing would happen.

1 Like