Prevent rules from cascading execution

Hi,

I have a rule that is triggered by something like Item MyItem changed. As “MyItem” is a hardware object this rule gets to execution in two possible ways:

  • by a hardware event (e.g. a knob is touched)
  • by some of my rules which changes the Item state with sendCommand/postUpdate

My issue is that a rule which does a sendCommand/postUpdate has to decide if it’s necessary that the other rule is also triggered. Sometimes I want to execute all rules defining MyItem changed after updating the state; sometimes the execution should simply omit these rules.

At the first try I used postUpdate instead of sendCommand and thought that it should do. But I misunderstood the meaning of postUpdate. My actors didn’t get the new values and the other rules were still executed.
Now I followed my second approch which seems to work at first sight:

var Boolean blockRules = false

rule "Samplerule"
when
  <Somthing happend. E.g. user pushed a button>
then
  if (sampleCondition_1) {
    blockRules = true // do NOT execute other rules
    MyItem.sendCommand(NEWVALUE)
  }
  if (sampleCondition_2) {
    MyItem.sendCommand(NEWVALUE) // DO execute other rules
  }
  Thread::sleep(500) // Is this necessary? I do not know how "fast" or multi-threaded rules execution is
  blockRules = false
end

rule "Second Rule"
when
  Item MyItem changed
then
  if (!blockRules) {
    // Some other tasks
  }
end

Anyhow I wanted to ask if this is the best method to solve my issue or if there are already patterns for this that can do better. Also I do not know if there are “side-effects” which I haven’t figured out so far.

Thanks for reading and discussion this topic!
Greetings from Germany!

Here just some thoughts:

  • not sure how quickly your rules can be triggered in succession and what would happen if if triggers the second time while still being executed; you could avoid this with a re-entry lock (http://docs.openhab.org/configuration/rules-dsl.html#concurrency-guard) for the first rule
  • how fast the system is depends on your infrastructure, you can of course always experiment; an alternative might be to move the statement blockRules = false to the beginning of this rule; as the scope of blockRule is global (meaning valid for this whole file), blockRule would keep the status it has when exciting the first rule (until the first rule gets triggered again)
  • and that gets to again the question how quickly your rule can be triggered again; it may result in weird behaviors if your first rule gets triggered with very high frequency (this would especially relevant if you use changes in groups as a trigger, as they may cause as many trigger events as there are members to this group)
  • and just for completeness, of course all rules that depend on blockRules would need to be in the same file, as the scope of such a variable extends only to this specific rule file
  • lastly, you could build in the logic into the first rule already; it all depends how complex your logic is, but consider a switch statement if you have a lot of conditions;
  • you could evaluate use groups and filter your items accordingly, use virtual items, etc, search the forum for “design patterns” (look for those referring to groups or virtual items); there are a few ingenious posts out there; though your post does not provide enough info and it’s hard to tell whether this might be useful in your case

Going back to your first approach, did you try using received command instead of changed as the trigger? A postUpdate will then not trigger the rule, but a sendCommand or adjustment in a UI will.

1 Like