[rules-users] Ruleflow not working with stateless session in drools-server 5.5.0.Final

tslonaker tslonaker+drools at gmail.com
Tue Feb 5 10:03:58 EST 2013


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?




--
View this message in context: http://drools.46999.n3.nabble.com/Ruleflow-not-working-with-stateless-session-in-drools-server-5-5-0-Final-tp4021624p4022072.html
Sent from the Drools: User forum mailing list archive at Nabble.com.



More information about the rules-users mailing list