首页 技术 正文
技术 2022年11月8日
0 收藏 646 点赞 1,807 浏览 2585 个字

整理了下最近在项目中使用drools出现的问题,幸好都在开发与测试阶段解决了,未波及到prod。

首先看这样两条规则:

/**
* 规则1_set默认利率a
*/
rule "rate_default_a"
no-loop true
when
$request:AmountRateRequest(calculateEnum == CalculateEnum.INTEREST || calculateEnum == CalculateEnum.AMOUNT_INTEREST)
$response:AmountRateResponse(rateMap not contains LoanTermEnum.LOANTERM3)
$data:DroolsData()
then
DroolsClient.logger.debug("{}执行规则{}", $response.getUserId(), drools.getRule().getName());
$response.getRateMap().put(LoanTermEnum.LOANTERM3, RateFactory.DEFAULT_RATE_A);
update($response);
end/**
* 规则2_set默认利率b
*/
rule "rate_default_b"
no-loop true
when
$request:AmountRateRequest(calculateEnum == CalculateEnum.INTEREST || calculateEnum == CalculateEnum.AMOUNT_INTEREST)
$response:AmountRateResponse(rateMap not contains LoanTermEnum.LOANTERM3)
then
DroolsClient.logger.debug("{}执行规则{}", $response.getUserId(), drools.getRule().getName());
$response.getRateMap().put(LoanTermEnum.LOANTERM3, RateFactory.DEFAULT_RATE_B);
update($response);
end

理想的情况:当规则fire后,rate_default_a规则实行,并set3期利率,得到结果后,由于不满足b规则的when条件(rateMap中3期利率已经存在),则不会继续执行rate_default_b,一切正常,

实际的结果:a执行后触发b、b执行后触发a,造成死循环

原因分析:

  肯定是因为when条件约束失败,导致重复触发,而与规则中修改所相关的就是

$response:AmountRateResponse(rateMap not contains LoanTermEnum.LOANTERM3)

  在drools中,不能通过contains来判断java的map对象是否containsKey。contains 只能用于对象的某个Collection/Array 类型的字段与另外一个值进行比较,作为比较的值可以是一个静态的值,也可以是一个变量(绑定变量或者是一个global 对象),不能操作map。如果需要判断map,建议使用map[keyName]的方式,比如我们这条规则,可以修改为:

$response:AmountRateResponse(rateMap[LoanTermEnum.LOANTERM3] == null)

来做,即可正确判断map的某个值是否为空。

同时对规则中出现的no-loop进行分析:  

  网络中能找到的大部分回答:no-loop属性的作用是用来控制已经执行过的规则在条件再次满足时是否再次执行。默认情况下规则的no-loop属性的值为false,如果no-loop 属性值为true,那么就表示该规则只会被引擎检查一次

  实际效果:no-loop所说的只执行一次,是说当本条规则内如果更新了fact,不会重新触发本条规则的执行。如果像我们上面代码中的情况,a规则和b规则本身都有no-loop true,但a中的udpate仍可以触发b的执行,b也可以触发a。

  如果需要让某条规则只能触发一次,则不能靠no-loop,需要使用lock-on-active true来做。同时注意:虽然规则只能被执行一次是可以做到的,但对于一些场景中,某些规则不希望被触发,并不只是限制次数,还需要结合具体业务来做。

结论和改进:

  1. 不要使用contains操作map,采用map[keyName]的形式

  2. 规则导致的死循环可能有很多种形式,a触发a、ab间相互触发,都可能引起很坏的结果,上线前要谨慎。

  3. 建议在每条规则执行前后增加日志,当出现死循环、或其他不符合预期的结果时能快速定位,方便追踪。

  4. 建议把怀疑有问题的语句拆成最小的单元执行。比如对我们上面的代码稍微修改,只保留一条规则:

/**
* 规则1_set默认利率a
*/
rule "rate_default_a"
no-loop true
when
$request:AmountRateRequest(calculateEnum == CalculateEnum.INTEREST || calculateEnum == CalculateEnum.AMOUNT_INTEREST)
$response:AmountRateResponse(rateMap not contains LoanTermEnum.LOANTERM3)
$data:DroolsData()
then
DroolsClient.logger.debug("{}执行规则{}", $response.getUserId(), drools.getRule().getName());
$response.getRateMap().put(LoanTermEnum.LOANTERM3, RateFactory.DEFAULT_RATE_A);
update($response);
end

  虽然不会导致死循环,但也无法说明到底是因为contains有效、还是no-loop true不触发自身,具体是哪行导致的结果正常。如果我们去掉no-loop true,就会发现依然出现了死循环,发现是contains的问题。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,488
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,903
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,736
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,487
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,127
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,289