基于 Drools 计时器的规则会话始终驻留在内存中并导致内存泄漏

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

我是 Drools 的新手。我想在触发规则后延迟 5 秒(并且只延迟一次)。所以,我使用 timer(int:5s) 来做到这一点。但是我发现规则执行后,我的控制台应用程序永远不会终止,它的 javaw.exe 进程仍然存在于我的任务管理器中。唯一的方法是调用 ksession.dispose()。但这是不可接受的,因为在我们的集群架构师中很难找到这个 ksession。

那么,有没有办法让ksession在规则执行后自动销毁?

这是我的简单测试用例:

  1. 主要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 文件

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

    输出将是:

    Started...
    Ended
    Finished
    

但我的控制台应用程序永远不会终止。有什么不对?我在 Drools 5.6.0 Final 和 6.4.0 Final 中都对其进行了测试。但是,他们两个都有同样的问题。我认为 ksession 应该被处理掉,因为 timer(int:5s) 不是间隔计时器。

计时器 运行 与托管会话的线程并行并使会话保持活动状态。在某种程度上,它们旨在用于 运行 不确定的会话,即未开始调用 fireAllRules。

以下情况应该可以让您完全关机:

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

你的会话是这样开始的:

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

编辑

如果您在任何情况下都需要调用 halt,您可以添加另一个具有否定条件的规则,该规则会立即调用 halt。

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

提示:否定条件X是不是not X

根据 laune 的出色回答,我修改了我的 drl 文件以确保 drools.halt() 将始终被命中。 (注意:v6.4.0 Final 是可以的。但是 v5.6.0 Final 会为 do 子句抛出异常)

dialect "mvel"
rule "Hello World"
timer(int:5s)
when
    m : Message()
    if ( m.status == Message.HELLO)
    do[hello]
then
    System.out.println( "other status" );
    drools.halt();
then[hello]
    System.out.println( "Hello!" );
    drools.halt();

结束