流口水,在事件发生后添加等待

Drools, add a wait after event occurred

我是 drools 的新手,希望尝试根据等待时间建立不同的规则,例如...

如果规则已经触发。 然后等待 5 分钟,然后 active/allowed 再次触发。

只是通读文档,但以最简单的形式,想知道这在 snippet/rule 中是如何工作的吗?还有任何关于好的文档的建议可以阅读以了解更多关于 drools/pam?

package com;

//a rule
rule "TimeBasedRule"

dialect "mvel"

    when
        debug : com.DataObject(fieldName == "ABC" );
        
    then
        System.out.println("Field Name: " + debug.field_name);
end

一般来说,您不应该首先考虑规则-class 公民。您的第一个 class 公民是您的规则输入或事件。规则只是逻辑。这就像习惯于将特定的“if”语句视为一个对象——它根本上不是同一件事,它有点过程控制逻辑。

这里的诀窍是改变你对场景的思考方式,而不是思考规则,而是思考触发它的情况。

根据你对问题陈述的非常模糊的描述,让我们充实一下。假设我们有一个应用程序,旨在在设备电池电量不足时提醒用户。一旦电池电量不足,我们应该向用户发送警报,但如果之前的警报是在过去 15 分钟内发出的,则不会。因此,例如,如果我们在 1:00 发送警报,则下一个警报不会早于 1:15.

发送

让我们假设我们有一个向我们发送读数的设备,例如温度计。该温度计向我们发送温度读数,但也包括一些状态信息,例如电池电量是否不足。一旦它开始指示电池电量低,那么我们将不得不开始考虑我们的特定用例,因为温度计获取读数的频率比我们希望用户收到警报的频率更高。


那么我们如何实现呢?方法有很多种,和往常一样,最好先从逻辑上考虑一下,然后再尝试将其转化为规则。

第一种方法是使用某种标志,例如指示最后一次电池电量不足警报的发送时间——您可以使用 date/time-like 表示来跟踪这一点。

rule "Low battery alert - tracked via flag"
when
  // The condition which indicates the battery is low
  ApplianceStatus( lowBattery == true )

  // The last time the alert was raised
  $lastAlert: OffsetDateTime()
  
  // Check if the last time the alert was raised >= 15 minutes ago
  Duration( toMinutes() >= 15 ) from Duration.between( $lastAlert, OffsetDateTime.now(ZoneOffset.UTC) )
then
  // Logic to send the alert
  sendAlert();

  // Update the 'last alert' time
  delete( $lastAlert )
  insert( OffsetDateTime.now(ZoneOffset.UTC) )
end

当然,这种方法的缺点是,我们需要将上次发出警报的时间传递到工作内存中。如果工作内存中没有 'last alert',则不会触发该规则。通过为该条件编写规则很容易解决这个问题 --

rule "Low battery alert - no previous alert"
when
  ApplianceStatus( lowBattery == true )
  not (OffsetDateTime())
then
  sendAlert();
  insert( OffsetDateTime.now(ZoneOffset.UTC) );
end

...但是我们有更多的选择。一般来说,在 Drools 中,可能至少有三种方法可以解决任何给定的问题,再加上十几种以非预期方式利用工具的方法。

第一个示例在云模式下运行良好,这是大多数 Drools 应用程序使用的默认模式和模式。但是,如果您 运行 处于 Stream 模式,则还有其他几个选项。

一种选择是在这样的声明中使用 @expires 标记:

declare Alert
  @role( event )
  @expires( 15m )
end

这使得每个警报事件在 15 分钟后自动过期。如果没有其他规则使用该事件,那么它可以从 KIE 会话中删除。您可以阅读更多关于流模式下的内存管理 here, or specifically about the metadata tags for declarations here。使用标签,您可以自定义事件的持续时间或发生时间,这使其成为附加时间操作的强大工具。

流模式的另一种选择是使用 temporal operators。编写这些运算符是为了让您可以针对一段时间内发生的事件编写规则。对于我们的低电量警报场景,我们可以想像地想要编写一个触发低电量警报的规则,但前提是我们的两个指示器至少相隔 X 分钟(例如,如果电池指示器不稳定或容易出错-positives.) 我链接到的文档包括一些特定场景的例子,以及所有操作符的详细解释,所以我不会在这里重现。


当然,如果我没有提到最基本的选项,那就是我失职了——只是在应用程序之外跟踪最后一个警报日期。如果您曾经转向分布式模型或希望在应用程序出现故障时确保高可用性,则需要在 drools 服务器的内存上下文之外跟踪此类事情。