简体   繁体   中英

Why does this Drools scenario cause an infinite loop?

I'm working on writing a rule set in Drools and the following situation causes an infinite loop by retriggering the rule:

rule "My Rule"
    when
        a1:ObjectA()
        b1:ObjectB(field1 > 0 || a1.field1 in (1,2,3))
        ObjectB(field2 > 10)
    then
        modify( b1 ) { setField3(5) };
end

The following rule change doesn't result in an infinite loop, ie, when a1 is no longer referenced within ObjectB:

rule "My Rule"
    when
        b1:ObjectB(field1 > 0 || field4 in (1,2,3))
        ObjectB(field2 > 10)
    then
        modify( b1 ) { setField3(5) };
end

Another scenario which doesn't cause an infinite loop is when I change the || to an && in the second when line:

rule "My Rule"
    when
        a1:ObjectA()
        b1:ObjectB(field1 > 0 && a1.field1 in (1,2,3))
        ObjectB(field2 > 10)
    then
        modify( b1 ) { setField3(5) };
end

From the Drools docs I understand that calling modify(){} will "trigger a revaluation of all patterns of the matching object type in the knowledge base," but since the field I'm modifying, field3 , isn't used in the LHS conditions, I didn't think it should reevaluate. However, I am faily certain it has to do with referencing a1.field1 within ObjectB , but I can't find a concrete reason why. Thanks in advance!

It matters at the object level, not the field level. Since you modify a1 , the rule is re-evaluated because it relies on the ObjectA objects in working memory. Note that the docs indicate it will "trigger a reevaluation of all patterns of the matching object type in the knowledge base." Not the parameter values.

One way you could avoid this would be to add a constraint like field3 != 5 on the left hand side. That is:

rule "My Rule"
when
  a1: ObjectA( field3 != 5 ) // <-- if field3 is already 5, don't fire the rule
  b1: ObjectB(field1 > 0 || a1.field1 in (1,2,3))
  exists(ObjectA(field2 > 10))
then
  modify( a1 ) { setField3(5) };
end

Basically you need to make the rule no longer eligible for re-fire.

Alternatively, depending on your structure you could try to use no-loop , but that only keeps the rule from refiring when immediately triggered by the right hand side. If you have multiple modifications/updates/etc going on, you could get into a "broader" looping scenario where multiple rules cause reevaluation. (Example: Rule A does a re-evaluate, no-loop keeps A from firing again; then B causes re-eval, so A can trigger because no-loop does not apply.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM