DRools: no-loop true attribute not working with update() method inference



I have a simple DRools package with a single rule whose DRL source is the following:

package com.rules.standard.isolatesFlags.GRUPPI_FAMIGLIE;

import org.package.path.ResultIsolate;

global org.apache.log4j.Logger logger;

function void finalizeIsolate(ResultIsolate isolate, Logger logger) {
    /* implementation */
}

function void setIsolateCSIFlag(ResultIsolate isolate, Integer csiAlarm, Logger logger) {
    /* implementation */
}

rule "ConfirmEsccolWasplab" 
    dialect "mvel"
    salience 10
    enabled true
    no-loop true

    when
      $a : ResultIsolate( deviceId == "WASPLAB_core" , microId == "h_W_ESCO" )
      $b : ViewPlateResult( plateStatus >= 60 , plateCode == "h_CCA" ) from $a.isolatePlates

    then
      finalizeIsolate($a,logger);
      setIsolateCSIFlag($a,new Integer(-1),logger);
      update($a);
end

Then, in my Java EJB I execute rules like the following:

kSession = kbase.newStatefulKnowledgeSession();
kSession.addEventListener(ruleListener);
            
logger.debug("Injecting global variabiles isTest and logger and EJB MicroRulesUtils into StatefulKnowledgeSession");
kSession.setGlobal("logger", org.apache.log4j.Logger.getLogger(MicroBusinessIsolateFlagsImpl.class));
                
kSession.insert(resultIsolate);
kSession.fireAllRules((int)MicroBusinessIsolateFlags.MAX_FIREABLE_RULES); //1000

ruleListener is a vlass which implements AgendaEventListener interface and in implementation of method beforeActivationFired I count how many rules are activated and fired for each single fact. In fact, in my EJB, after firing rules, I check:

if(ruleListener.getNumberOfFiredRules() >= MAX_FIREABLE_RULES) {
    logger.info("Isolate flags rules fired more than ",MicroBusinessIsolateFlags.MAX_FIREABLE_RULES, " times. Check configuration to prevent inference loops from occurring.");
    logger.info(ruleListener.getRulesActivationsLog()); //print fired rules and how many times
}

So, it always happens that this warning is showed. How is it possible? As I said, I have a single package with a single rule and with no-loop true attribute I woudl expect that the rules itsself is no more activated as consequence of its RHS. But it is. Is that a bug? Also after adding other rules of packages which are not activated (the conditions of the contained rules are not matched) then I always get thet rule logged as fired 1000 times (a loop). I am using DRools 5.0.1 and I am not allowed to upgrade it.

Answer

No, it’s not a bug. It’s how the feature works.

Calling update is functionally equivalent to calling ‘fireRules’. It’s as if we exited the current ‘fire rules’ flow, and then reran all the rules with new data. Since it’s a new run, there’s no previous executions, so no-loop doesn’t apply.

This is in comparison to insert (for example). When you call insert in the RHS of a rule, the engine merely re-evaluates subsequent rules in the current run. In this case, ‘no-loop’ does apply, because we’re still in the same run, and the previous executions remain.

no-loop is intended to keep the same rule from firing more than once in a single execution of the rules. It’s not intended to keep the rule from firing across multiple executions.

To make your rule not fire on update, you need to modify your left hand side to exclude the condition that is set on the right hand side. Since you’ve omitted your definition of the setIsolateCSIFlag function, I’ll make up a simple example instead:

rule "EXAMPLE"
no-loop
when
  Address( $locality: locality )
  $purchase: Purchase( sum > 0, tax == null )
then
  $purchase.calcualteTaxForLocality($locality); // sets 'tax' to some value
  update( $purchase );
end

Since the Purchase instance now has a non-null tax value, the rule doesn’t trigger again after the update. In your situation, you should update your conditionals (LHS) to not fire based on whatever the setIsolateCSIFlag method actually does. Or, alternatively, don’t call update.



Source: stackoverflow