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.
Advertisement
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
.