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
View this message in context: http://drools.46999.n3.nabble.com/Ruleflow-not-working-with-stateless-session-in-drools-server-5-5-0-Final-tp4021624p4022161.html> 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/drools/impl/StatelessKnowledgeSessionImpl.java?r1=63021da325036ec6fbdf4019e8c8293db21555ec&r2=fad9b951f44ac813e5faf50f097335c2a97007ae>
> .
>
> 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?
--
Sent from the Drools: User forum mailing list archive at Nabble.com.
_______________________________________________
rules-users mailing list
rules-users@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users