I am new to Drools and I am struggling with this ruleflow issue. Please let
me know if I have been posting this info to the wrong message board.
My situation is that I am working on converting our application from using
an expensive commercial rule engine to Drools. Our rule engine
implementation uses a stateless server and it heavily depends on ruleflows.
We could develop the rules using salience but that isn't ideal.
It seems to me that there is still a bug in drools-server when using
ruleflows in a stateless session. It seems that the fix for issue 2718
<
https://issues.jboss.org/browse/JBRULES-2718> partially fixed the
problem. There is an easy workaround if you are coding your solution in
Java. You just create a new instance of the Stateless session every time.
But in drools-server I don’t have any control over that.
tslonaker wrote
I found a much easier way to recreate the problem described in my
previous
post. I believe I have also found the root cause of the problem. Below
are the steps to recreate the issue:
- Create a simple ruleflow and rules and compile them into a rule package.
- In code create a stateless session
- In a loop
o Create a fact
o Create a new execution batch with the following commands
- Insert the fact from above
- Start Process
- Fire All Rules
- Get Objects
o Execute the batch
o Check the results (number of rules that ran)
I posted before that the problem didn’t happen while executing locally
(not in drools server). I didn’t realize this before, but adding a loop
that executes the rules multiple times with the same session recreates the
problem.
Below is code that will recreate the issue. Notice that the code below
creates one instance of ksession and reuses it in the loop.
//Setup
KnowledgeBuilder kbuilder =
KnowledgeBuilderFactory.newKnowledgeBuilder();
//The package includes the ruleflow
kbuilder.add( ResourceFactory.newFileResource(
("YourRulePackage_WithRuleflow.pkg") ), ResourceType.PKG );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
*
//Create the stateless knowledge session outside the for loop
StatelessKnowledgeSession ksession =
kbase.newStatelessKnowledgeSession();
*
//Loop through executing the rules with the same data 3 times
for (int x = 0; x < 3; x++)
{
//Create a new instance of the input fact
FactType inputDataType = kbase.getFactType("SimpleRuleflowTest",
"Input");
Object inputData = inputDataType.newInstance();
inputDataType.set(inputData, "Name", "Test data");
//Create a new instance of the command list
List cmds = new ArrayList();
cmds.add( CommandFactory.newInsert( inputData ));
cmds.add( CommandFactory.newStartProcess( "TestRuleflow"));
cmds.add( CommandFactory.newFireAllRules("rules"));
cmds.add( CommandFactory.newGetObjects("output"));
//Execute the rules
ExecutionResults results = ksession.execute(
CommandFactory.newBatchExecution( cmds ) );
//Get the number of rules that ran
Object rules = results.getValue("rules");
System.out.println("Rules that ran: " + rules.toString());
}
Each iteration through the loop should fire 3 rules. Running the code
above you should get the following output:
Rules that ran: 3
Rules that ran: 1
Rules that ran: 1
I spent several hours researching the drools source code and I believe I
have found the problem. What I have found is related to
Issue 2718 <
https://issues.jboss.org/browse/JBRULES-2718>
.
Check out the change made for this issue:
2718 fix
<
https://source.jboss.org/viewrep/Drools/drools-core/src/main/java/org/dro...
.
Below is a snippet from the code that was modified for issue 2718. The
“if (!initialized)” block was added. The code loops through event
listeners on the wm object and adds them to the stateless session’s
listeners. This works fine for the first rule execution. But the next
rule execution creates a new instance for wm. Therefore it also creates
new instances of listeners for wm. So we have a new instance of wm and
the stateless session is pointing to the old listeners from the first
instance of wm. I believe that is why it only runs correctly one time. It
seems that that the “if (!initialized)” block of code needs to execute
every time newWorkingMemory() is called.
public StatefulKnowledgeSession newWorkingMemory() {
:
:
ReteooWorkingMemory wm = new ReteooWorkingMemory(
this.ruleBase.nextWorkingMemoryCounter(),
this.ruleBase,
(SessionConfiguration) this.conf,
this.environment );
:
:
*
if (!initialized) {
*
// copy over the default generated listeners that are used for
internal
stuff once
for (org.drools.event.AgendaEventListener listener:
wm.getAgendaEventSupport().getEventListeners()) {
this.agendaEventSupport.addEventListener(listener);
}
for (org.drools.event.WorkingMemoryEventListener listener:
wm.getWorkingMemoryEventSupport().getEventListeners()) {
this.workingMemoryEventSupport.addEventListener(listener);
}
InternalProcessRuntime processRuntime = wm.getProcessRuntime();
if (processRuntime != null) {
for (ProcessEventListener listener:
processRuntime.getProcessEventListeners()) {
this.processEventSupport.addEventListener(listener);
}
}
initialized = true;
}
:
:
}
So, I tested this theory in my test function. I used reflection to flip
the “initialized” flag at the bottom of my loop. I did this to force the
listeners of the stateless session to be refreshed for every execute call.
It worked! The other nodes in the ruleflow now get executed after the
first rule execution. Below is a snippet of my modified test code:
//Same As Above
:
:
//Create the stateless knowledge session outside the for loop
StatelessKnowledgeSession ksession =
kbase.newStatelessKnowledgeSession();
//Loop through executing the rules with the same data 3 times
for (int x = 0; x < 3; x++)
{
:
:
//Flip the initialized flag to false through reflection
*
Field field =
StatelessKnowledgeSessionImpl.class.getDeclaredField("initialized");
field.setAccessible(true);
field.setBoolean(ksession, false);
*
}
Running the code above you should get the following output:
Rules that ran: 3
Rules that ran: 3
Rules that ran: 3
My original problem deals with drools-server. It isn’t possible for me to
flip the initialized flag to false in that scenario. So, is there any
sort of workaround that would get me past this issue when using
drools-server?
--
View this message in context:
http://drools.46999.n3.nabble.com/Ruleflow-not-working-with-stateless-ses...
Sent from the Drools: User forum mailing list archive at
Nabble.com.