Reliable preventing of "Multiple simultaneous rule execution error"

@bravenel @bertabcd1234

I need a very reliable handshaking between RM Rules.
For this reason I am using Hub Variables similar to Private Boolean but with nice names such as *_Busy

Here is my test RM rule:
image

I need to use a "Delay" because "Wait for Event : Elapsed Time" always cancelled and rule will not execute to the end.

And here is a related log:


Testing is simply toggling of Test VSWitch
Once in a while I am getting "Multiple simultaneous rule execution error".
This smells like some sort of Race Condition.

I can make it 100% reliable (did not get a failing condition) by adding (Private Boolean(true) is true(T) [TRUE]) as a Required Expression.
However I am using some RM rules triggerless as subroutines. In this case the Required Expression does absolutely nothing. I can make this working with two RM rules where extra rule simply prevents triggering of main rule.
Something like this:

My questions are:

  1. Is this true true Race Condition I found?
  2. Is it possible to create a single rule 100% protected from multiple runs?

It's not so much a race condition as what it says, two instances running at the same time. Delays embedded in IF-THEN will do this. If triggered during the delay, there goes a second instance, the IF-THEN runs while the other instance is still pending, and it's not going to end well.

Use Required Expression of Private Variable True. First action, set Private Boolean to false. Last action, set Private Boolean true again. Once PB is false, the Required Expression becomes false, and rule can't be triggered until it is true again. Thus, once the first instance starts running, a second instance cannot be triggered. (In the case of an extremely chatty trigger device, even this could fail -- the fix for which is to debounce the device.)

2 Likes

Thank you for the clarification.
This is exactly what I am doing. So far this is a very good solution for but only for triggered rules.
However if I want a triggerless rule to be used as say, subroutine (I have many cases like this) I have to create a second wrapper rule rule and use this wrapper instead. This is doable but unfortunately becomes more messy (harder to create nice names for main rule and wrapper).

I wonder if an if boolean = false, exit rule would fit this case where the rule would be triggered by another?

I don't understand what you saying the problem is. For a subroutine rule, does it have delay embedded in IF-THEN? That is really the only problem.

1 Like

Yes. The same triggerless rule with delay embedded in IF-THEN and called from another rule does not have a multiple run protection. I am not considering this as a problem. This is inconvenience because a wrapper rule must be created for protecting multiple runs. For the triggered rule the protection is done by Required Expression which is not applicable to the triggerless rules.

Yes, but since you are calling it you can protect where the call happens using a Hub Variable. For example. the subroutine could set a Hub Variable to false when it starts, and true when it finishes. The calling rule could test that Hub Variable before making the call. It could, as an example, Wait for Condition of that Hub Variable being true, and then calling the subroutine.

Maybe my wording was not clear (sorry about this) but this is exactly what I am doing as we speak.

I draw flow charts that show what each rule does so that I don't accidentally have multiple rules firing unnecessarily at the same time. Usually when I find a problem on my flow chart, the solution is a simple "IF THEN" condition at the beginning of each conflicting rule action to make it's execution more specific to avoid the simultaneous triggering.

I was looking for the solution inside the rule itself.
For the triggered rules the appropriate Required Expression solves the issue.
But for the triggerless rules extra rule is required.
For the maintainability my golden rule is - any changes must be done in one single place.
Yours approach not only requires changes in multiple places but also requires to update this diagram. In my case this is no go:
First - I am to.....o lazy to make changes in many places.
Second - everything must be self explanatory without creating any extra documentation.

The goal is obviously always to make a change in one place. That's precisely why a flow chart is a good idea. It allows you to visualize your project flow so that you can optimize it properly to prevent dual triggers or other issues. Why do you see adding a condition to a given rule as not a solution "inside the rule itself"?

A flow chart is always a good idea. It does not necessarily mean that it's existence implies some degree of inefficiency within the system it is visualizing.

At this point, I have over 100 rules in rule machine. It would be impossible for me to keep track of everything without a flow chart.

Hi, I've seen this term before. What does "denounce" mean?

debounce.

It means to capture rapid events from a device and only allow a single event to be sent, assuming that all of the fast events happen within a short time frame, like 500 milliseconds or 1 second. For example, my one contact sensor would send off two open events in quick succession when the contact opened. That would cause a problem triggering a rule twice that should only be triggered once.

2 Likes

Now I understand, thanks so much,:+1:

What's your recommended way to debounce a device (like a contact)? Is there any way to do it without creating a virtual contact?

Not really that I know of. It depends on how long the interval is. If it is quite short, anything triggered by it may trigger a second time, even before some logic could intervene.

The fastest way I know without using a virtual device is to use the Private Boolean Required Expression approach in RM. From the first trigger, to getting the Required Expression to be false, which drops the event subscription, may be fast enough to beat a second trigger event from triggering the rule. But if the second event is too fast, that approach won't work.

I'm sure there are other ways to do this, involving custom apps and semaphore-like logic to prevent double activations from fast events. But each of those is going to requires something to act as a carrier of an event, i.e., a virtual device. Perhaps someone could write a driver that debounces, but that's not my area of knowledge. It's tricky.

2 Likes