为监控程序和时间敏感程序编写规则 <o:p></o:p>
作者:Edson Tirelli <o:p></o:p>
在讨论完关于编写规则的抽象概念以后,我打算停一下,讨论一些真实的规则引擎用例以及怎样对这些用例编写规则。<o:p></o:p>
我发送了邮件到用户列表中询问大家喜欢更详细的讨论哪些用例,然后我开始收到一些反馈。在这篇文章中,我将讨论一个由Neil Goldman建议的主题,同时也是分享他对监控程序和时间敏感程序建立规则的一些想法。
这篇文章不是讨论关于事件流处理的范围,这个专题与本文有所关联,但是这个专题所涉及的面太广而不能被包括在本文中。<o:p></o:p>
在这个例子中我将使用Drools,但是其中的思路可以用于其它规则引擎。<o:p></o:p>
监控应用
监控应用是用于对传感器(温度,天气,动作等等)或代理(网络单元,管理系统,管理Bean等等)传递的输入进行监控并最终采取行动。它们通常需要以接近实时的方式进行工作,被设计用来对系统状态的改变做出反应。<o:p></o:p>
问题是:我怎样才能架构我的应用程序才能利用到规则引擎的优点来设计监控程序呢?<o:p></o:p>
让我们从一个简单的例子开始讨论:假设用一个监控程序是为空调系统设置的,它必须保持温度在某一个范围之内。<o:p></o:p>
完成它的一个简单方法是使用规则引擎中有状态的working memory,它反射系统的状态并且规则针对状态的改变做出反应。上面例子中系统的状态是由传感器提供,因此将传感器模型作为Fact是最好的方法。规则将基于这些传感器Fact来做出决定。因此,你的规则可以是:
- global org.drools.examples.acsmonitoring.AirConditioningSystem acs;
- rule "turn ACS on"
- when
- TemperatureSensor( celsiusGrade > 25 )
- then
- acs.turnOn();
- end
- rule "turn ACS off"
- when
- TemperatureSensor( celciusGrade < 20 )
- then
- acs.turnOff();
- end
- rule "turn ACS on"
- when
- WeatherSensor( $weather : weather )
- TemperatureRange( weather == $weather, $max : maxTemperature )
- TemperatureSensor( celciusGrade > $max )
- then
- acs.turnOn();
- end
- while( /* an exit condition */ ) {
- sensorReader.update( sensor );
- wm.modify(sensorHandle, sensor );
- wm.fireAllRules();
- // wait for the next polling slot
- }
我们这里所说的是推论时间。如果用作推论的时间,显然需要将它看作fact模型。
引用Neil Goldman所说:<o:p></o:p>
" 你不要想规则条件读取操作系统的时钟作为匹配条件的一部分,因为当这些条件被评估时,你只能做很小的控制。系统时钟以一种非常高的频率进行变化,而规则引擎无法察觉这么小的如此高频率的变化。<o:p></o:p>
你希望你的规则可以对一个伪时钟具有敏感性,那
a) 你可以用可控制的方式更新,并且
b) 规则引擎可以被告知更新. "<o:p></o:p>
是的,你希望有一个可控制的时钟用来推论。一个好的想法是将时钟像之前例子中那样作为一个传感器。在前面的例子中,应用控制传感器何时和怎样被更新,以保持系统状态的连续性。同样应用可以控制规则伪时钟何时和怎样获得更新。
这一方法有一个优点,如下所列:<o:p></o:p>
- 系统持续性: 你可以保证没有额外的,未知的或预知的事件将导致fact的非连续性(所有系统管理员都知道当每日备份期结束时,及时返回一个小时前的状态是让人头痛的事情)并且应用在可控情况下处理这些情况是很棒的。<o:p></o:p>
<o:p> </o:p>
- 自动测试: 如果你的规则是在伪时钟上推论,你可以将时钟设置需要测试的特定场景以方便编写测试,你的伪时钟可以在预定义的时间间隔上用真实时钟同步。<o:p></o:p>
<o:p> </o:p>
- 运行模拟的能力: 假设你有一个资产管理系统(考虑最佳分类),那里有超过10000条规则来管理你的客户部门的每一个单独的资产,并且你的那些富豪级的客户过来问“倘若...?”。任何有模拟系统工作经验的人知道,一个基本的要求是有一个伪时钟。因此,如果你的10000条规则参照伪时钟编写,将这些规则将模拟特性加入应用仅仅是一个时钟设置的问题…另一方面,如果规则使用真实的时钟,你只能调整规则或更改服务器时间了…<o:p></o:p>
<o:p> </o:p>
要注意的时,上面所提及的问题,没有严格的限制要求定期将你的伪时钟与系统时钟同步,只要你拥有控制,何时和怎样更新伪时钟都可以。
<o:p></o:p>
现在我们从代码级别来了解一下所说的情况。假设你有一个任务计划应用程序,并且你想编写的规则将在计划的时间到达后运行你的任务,或者前一个必须的任务已经完成时。你的规则应当如下:
<o:p></o:p>
- rule "Fire based on time"
- when
- PseudoClock( $currentTime : currentTime )
- $t : Task( preReq == Task.PR_TIME, executedAlready == false, scheduledTime <= currentTime )
- then
- $t.execute();
- end
- rule "Fire based on task"
- when
- $pr : Task( firedAlready == true )
- $t : Task( preReq == Task.PR_TASK, executedAlready == false, preReqTask == $pr )
- then
- $t.execute();
- end
<o:p> </o:p>
你可能注意到在计划时间和当前时间比较时用了一个“<=”操作。这是因为通常无法保证你的规则正好在指定时间运行(除非运行在一个实时的平台),但是将在计划时间后尽早的执行。因此对时间的条件判断使用范围或一个起点来判断要比绝对值好。<o:p></o:p>
时间敏感的应用
时间敏感应用程序是根据时间进行推论或反应的应用。例如:账单应用,运行模拟的应用,任务计划等等。
在这样的应用中,规则将直接或间接的依赖于时间。在这里重点注意的是不要搞混将时间作为数据还是元数据应用到规则的区别。规则引擎通常有功能特性用来将时间作为元数据处理,比如允许特性指定一个规则的生效和失效时间。<o:p></o:p>
好了,我们已经从规则的方面来看你的问题,但是应用程序需要做什么呢?答案是:简单的保持更新传感器数据。可以通过几种办法完成,依赖于系统工作的方式,但最终通常使用查询和事件两种方式。如果你对ACS进行查询,代码如下:<o:p></o:p> 上面是非常简单的规则,但是它们示范了这个概念。下面是利用天气传感器获得的数据建立对天气有更精密反应的规则模型:
<o:p></o:p>