You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Drools 5.5.0.Final迁移至9.44.0.Final时的调用死锁问题

Drools 5.5.0.Final 迁移至 9.44.0.Final:规则调用Java方法触发Query导致会话挂起

问题现象

将Drools从5.5.0.Final升级到9.44.0.Final后,原有规则中调用Java方法、Java方法内再调用Drools Query的逻辑出现执行挂起问题。旧版本中该逻辑可正常运行,但新版本执行时会陷入无响应状态。

调试发现:KieSession的Agenda处于FIRING状态,Query调用会在Agenda中新增一个被永久阻塞的任务,无法返回代码。

相关代码示例

Drools 规则代码

////
// DROOLS
////
query javaToDrools
  ves : Data()
end

rule "INSERT: New Item"
  when
    $data: MyData($id:id)
  then
    System.out.println("Insert Data: " + $id);
    insert(new Data($data));
    myJavaClass.droolsToJava();
end

Java 代码

////
// JAVA
////
public void droolsToJava() {
    QueryResults results = session.getQueryResults("javaToDrools");
    results.forEach(res -> {
        res.toString();
    });
    session.fireUntilHalt();
}

问题调用链分析

挂起发生在以下调用链中:

StatefulKnowledgeSessionImpl.getQueryResults
-> StatefulKnowledgeSessionImpl.internalGetQueryResult
-> StatefulKnowledgeSessionImpl.evalQuery
-> StatefulKnowledgeSessionImpl.addPropagation -> 添加了Propagation任务

在evalQuery方法中,executeQuery.getResult()始终无法获取结果,陷入无限循环,无法在向KieSession插入事实的同时调用Query。

原因分析

Drools 新版本(尤其是7.x之后的Kie架构重构版本)对会话的并发和状态管理做了严格限制:

  • 当Agenda处于FIRING状态(规则正在执行then块逻辑)时,调用getQueryResults会触发新的规则传播任务,但此时会话正处于规则执行的临界区,新任务无法被调度执行,导致死锁。
  • 旧版本的StatefulKnowledgeSession对这种嵌套调用的限制较宽松,允许在规则执行过程中同步执行Query并触发新的规则传播,但新版本的KieSession引入了更严格的状态检查和锁机制,避免并发问题的同时,也阻止了这种不安全的嵌套操作。

解决方案

方案1:异步执行fireUntilHalt,避免阻塞当前规则线程

将Java方法中的fireUntilHalt改为异步执行,跳出当前规则执行的临界区:

public void droolsToJava() {
    QueryResults results = session.getQueryResults("javaToDrools");
    results.forEach(res -> {
        res.toString();
    });
    // 异步启动规则持续触发,不阻塞当前规则执行线程
    new Thread(() -> session.fireUntilHalt()).start();
}

方案2:重构逻辑,将Query操作移至规则内部

如果Query的目的是获取刚插入的Data对象,可直接在规则then块中处理,无需调用Java方法:

rule "INSERT: New Item"
  when
    $data: MyData($id:id)
  then
    System.out.println("Insert Data: " + $id);
    Data newData = new Data($data);
    insert(newData);
    // 直接在规则中处理Data对象,替代Java层的Query逻辑
    System.out.println("Processed Data: " + newData);
end

方案3:在规则执行完成后再触发Query和规则传播

调整执行顺序,确保Query调用时Agenda处于IDLE状态:

// 先插入事实并执行所有规则
session.insert(new MyData(1));
session.fireAllRules();
// 此时规则执行完毕,可安全执行Query
QueryResults results = session.getQueryResults("javaToDrools");
results.forEach(res -> {
    res.toString();
});
session.fireUntilHalt();

内容的提问来源于stack exchange,提问作者Marc Gil Sendra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:35:06