Search code examples
javamemory-leaksdrools

Drools timer based rule session always resides in memory and cause memory leak


I'm a newbie to Drools. I want to delay 5s after I fired the rule (and just for one time). So, I use timer(int:5s) to do that. But I found that after the rule executed, my console application will never be terminated and its javaw.exe process still exist in my task manager. The only one way is to call ksession.dispose(). But it's not acceptable because it's hard to find this ksession in our clustering architect.

So, is there any way to make the ksession automatically disposed after the rule executed?

Here are my simple test case:

  1. main class

    public class App {
        public static void main( String[] args ) {
            System.out.println("Started...");       
    
            KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
            kbuilder.add(new ClassPathResource("Timer.drl", App.class), ResourceType.DRL); 
            KnowledgeBase kbase = kbuilder.newKnowledgeBase();
            StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();        
            ksession.fireAllRules();        
    
            System.out.println("Ended");
        }
    }
    
  2. drl file

    package myDrools.TimerTest1
    
    rule "Your First Rule"
    
    timer(int:5s)
    
    when
        eval(true)
    then
        System.out.println("Finished");
    end
    

    The output will be:

    Started...
    Ended
    Finished
    

But my console application will never be terminated. Is there something wrong? I tested it both in Drools 5.6.0 Final and 6.4.0 Final. However, both of them has the same issue. I think the ksession should be disposed since timer(int:5s) is not an interval timer.


Solution

  • Timers run in parallel to the thread hosting the session and keep the session alive. In a way, they are meant to be used in sessions running indeterminate, i.e., not started calling fireAllRules.

    The following scenario should give you a clean shutdown:

    rule  "Your First Rule"
      timer( int:5s )
    when
    then
      System.out.println("Finished");
      drools.halt();
    end
    

    And your session is started like this:

    kieSession.fireUntilHalt();
    System.out.println( "return from fireUntilHalt" );
    kieSession.dispose();
    

    Edit

    If you need to call halt in any case you can add another rule with the negated condition which calls halt right away.

    rule "stop if not met"
    when
        // negated condition X
    then
        drools.halt();
    end  
    

    Hint: The negated condition X is not not X!