首页 > 解决方案 > 如何让规则只触发一次?

问题描述

假设以下规则侦听具有特定标识符的事件。每个标识符只应处理一个事件。

rule "SampleRule"
dialect "mvel"
no-loop true
when
    Event( $identifier : identifier)
    not(EventHandler( identifier == $identifier )) 
then
    EventHandler $h = new EventHandler();
    $h.setIdentifier( $identifier );
    insert( $h );
end

活动类别:

...

@javax.persistence.Entity
@org.kie.api.definition.type.Role(org.kie.api.definition.type.
                         Role.Type.EVENT) // line break just for SO
public class Event implements java.io.Serializable {

  static final long serialVersionUID = 1L;

  @javax.persistence.GeneratedValue(generator = "STATUSNOTIFICATION_ID_GENERATOR", strategy = javax.persistence.GenerationType.AUTO)
  @javax.persistence.SequenceGenerator(name = "STATUSNOTIFICATION_ID_GENERATOR", sequenceName = "STATUSNOTIFICATION_ID_SEQ")
  private java.lang.Long id;

  private java.lang.String identifier;

  public Event() {
  }

  public java.lang.String getIdentifier() {
    return this.identifier;
  }

  public void setIdentifier(java.lang.String identifier) {
    this.identifier = identifier;
  }
}

事件类是通过 Drools Workbench 配置的。除了将课程声明为 EVENT 之外,我没有更改任何其他内容。

事件插入规则引擎的方式:

KieServicesConfiguration conf = KieServicesFactory.newRestConfiguration(
            url, user, pass);
conf.setMarshallingFormat(FORMAT);   
KieServicesClient kieServicesClient = KieServicesFactory.newKieServicesClient(conf);
RuleServicesClient rulesClient = kieServicesClient.getServicesClient(RuleServicesClient.class); 
KieCommands commandsFactory = KieServices.Factory.get().getCommands();

while (hasEvent) {
  String identifier = ... // get the identifier of the event, events with same identifier possible, sometimes within same seconds, sometimes several minutes/hours in between

  Event event = new Event();
  event.setIdentifier(identifier);

  Command<?> insert = commandsFactory.newInsert(event, "notificationIdentifier");
  Command<?> fireAllRules = commandsFactory.newFireAllRules();
  Command<?> batchCommand = commandsFactory.newBatchExecution(Arrays.asList(insert, fireAllRules));

  ServiceResponse<ExecutionResults> executeResponse = rulesClient.executeCommandsWithResults("name_of_rules_package_incl_version", batchCommand);
  if (executeResponse.getType() == ResponseType.SUCCESS) {
    ...
  } else {
    ...
  }  
}                                                   

除了上面的“SampleRule”规则之外,我还启用了另一个规则,如果每个标识符的 EventHandler 存在,则从工作内存中收回事件:

rule "SampleRuleClear"
dialect "mvel"
no-loop true
when
    $E : Event( $identifier : identifier)
    EventHandler( identifier == $identifier )
then
    retract( $E ); 
end

实际上,不应该要求“SampleRuleClear”规则来防止重复。我只是在这里提到它的完整性。

我希望“SampleRule”规则每个标识符每个事件只触发一次。不幸的是,即使事件间隔很远,它也会触发多次。

标签: droolsrulesrule-enginekie

解决方案


推荐阅读