整理了下最近在项目中使用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的问题。

drools规则引擎中易混淆语法分析_相互触发导致死循环分析的更多相关文章

  1. Drools规则引擎-memberOf操作

    场景 规则引擎技术讨论2群(715840230)有同学提出疑问,memberOf的使用过程中如果,memberOf之后的参数不是集合也不是数组,而是格式如"1,2,3,4"的字符串 ...

  2. Drools规则引擎-如果判断某个对象中的集合是否包含指定的值

    规则引擎集合相关处理 在实际生产过程中,有很多关于集合的处理场景,比如一个Fact对象中包含有一个集合,而需要判断该集合是否包含某个值.而Drools规则引擎也提供了多种处理方式,比如通过from.c ...

  3. Drools规则引擎入门指南(一)

    最近项目需要增加风控系统,在经过一番调研以后决定使用Drools规则引擎.因为项目是基于SpringCloud的架构,所以此次学习使用了SpringBoot2.0版本结合Drools7.14.0.Fi ...

  4. drools规则引擎初探

    https://www.cnblogs.com/yuebintse/p/5767996.html 1.drools是什么 Drools是为Java量身定制的基于Charles  Forgy的RETE算 ...

  5. Drools规则引擎

    一.简介 Drools is a Business Rules Management System (BRMS) solution. It provides a core Business Rules ...

  6. Drools 规则引擎环境搭建

    一.关于 drools 规则引擎 前面写过一篇 Drools 规则引擎相关的文章,这篇文章主要记录一下规则引擎的环境搭建和简单示例.不熟悉 drools 的朋友可以看看这篇文章: 自己写个 Drool ...

  7. Spring Boot+Drools规则引擎整合

    目的 官方的Drools范例大都是基于纯Java项目或Maven项目,而基于Spring Boot项目的很少. 本文介绍如何在Spring Boot项目上加上Drools规则引擎. POM依赖 POM ...

  8. Drools规则引擎-判断集合(List)是否包含集合

    问题场景 在使用Drools规则引擎时,有朋友会遇到这样的问题,就是在when部分判断的两个参数都是集合类型,比如两个List,此时要判断一个集合是否包含另外一个集合的内容. 拿一个具体的例子来说明, ...

  9. SpringBoot2 整合 Drools规则引擎,实现高效的业务规则

    本文源码:GitHub·点这里 || GitEE·点这里 一.Drools引擎简介 1.基础简介 Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的 ...

随机推荐

  1. 基于WebGL架构的3D可视化平台—设备管理

    ---恢复内容开始--- 国内高层建筑不断兴建,它的特点是高度高.层数多.体量大.面积可达几万平方米到几十万平方米.这些建筑都是一个个庞然大物,高高的耸立在地面上,这是它的外观,而随之带来的内部的建筑 ...

  2. “AS3.0高级动画编程”学习:第二章转向行为(上)

    因为这一章的内容基本上都是涉及向量的,先来一个2D向量类:Vector2D.as (再次强烈建议不熟悉向量运算的童鞋,先回去恶补一下高等数学-07章空间解释几何与向量代数.pdf) 原作者:菩提树下的 ...

  3. Linux操作系统df相关问题解惑

    1.df 命令无法使用解决办法 问题分析: 1.1 df命令是通过/etc/mtab文件读取已挂载文件系统的信息,因此,df命令无法使用的原因的在于/etc/mtab文件被损坏或者丢失. 查看 mor ...

  4. 写给自己的小CASE

    一时的完美不代表什么,重要的是不断地学习和成长:直面挑战,不断进取.   摘自<看见成长的自己>.

  5. ViewPager中Fragment的重复创建、复用问题

    在ViewPager中的Fragment的生命周期  随着页面的切换 当前的展示页相邻的页面生命周期一直在变化 一开始 刚进入Activity时候,ViewPager默认初始化好前两个Fragment ...

  6. oracle数据入库

    oracle数据入库 注意:先要处理文件中的分隔符   将数据分列 创建为标准的sql语句   1.在oracle数据库中创建要入库的表如果有该表则不用创建(注:创建字段的数据类型要符合实际逻辑 va ...

  7. python中的继承和多态

    继承 继承的表现方式: class Animal(): pass class Cat(Animal): #animal是cat的父类,也可以说是基类 pass print(Cat.__bases__) ...

  8. python基础 (装饰器,内置函数)

    https://docs.python.org/zh-cn/3.7/library/functions.html 1.闭包回顾 在学习装饰器之前,可以先复习一下什么是闭包? 在嵌套函数内部的函数可以使 ...

  9. HDU2035

    #include <bits/stdc++.h> using namespace std; int fastpow(int a,int b,int k) { ; while(b) { ) ...

  10. JAVA实训第二次作业

    一维数组的创建和遍历. 声明并创建存放4个人考试成绩的一维数组,并使用for循环遍历数组并打印分数.要求: (1) 首先按"顺序"遍历,即打印顺序为:从第一个人到第四个人: (2) ...