Search code examples
droolsredhatbusiness-rulescomplex-event-processingdrools-fusion

Drools Fusion time sliding based windows


I cannot undestand how JBoss Drools inference engine works with complex event processing (drools fusion). Actually i created a rule in order to deny a transaction if more than 2 transactions occour in less than 5 seconds. Here is the rule

rule "more than 2 transaction in 5 seconds"
  when
    $transaction : Transaction( $id : id )
    Number(intValue > 2) from accumulate(
        $t : Transaction() over window:time(5s),
        count($t))

then
   $transaction.setDenied(true);
end

I set the session in streaming mode using the pseudo session clock. Here the java code

SessionPseudoClock clock = kSession.getSessionClock();
Transaction tx1 = new Transaction(new BigInteger("10000"), TransactionType.CREDIT_CARD, 1L);
Transaction tx2 = new Transaction(new BigInteger("2000"), TransactionType.CREDIT_CARD,2L);
Transaction tx3 = new Transaction(new BigInteger("50000"), TransactionType.DEPOSIT,3L);
Transaction tx4 = new Transaction(new BigInteger("100"), TransactionType.WITHDRAW,4L);

assertTransaction(kSession, tx1);

clock.advanceTime(6, TimeUnit.SECONDS);
assertTransaction(kSession, tx2);

clock.advanceTime(3, TimeUnit.SECONDS);
assertTransaction(kSession, tx3);

clock.advanceTime(1800, TimeUnit.MILLISECONDS);
assertTransaction(kSession, tx4);

where assertTransaction simple contains the following code:

kSession.insert(tx);
kSession.fireAllRules();

The transaction that trigger the rule match is the tx4 since tx2 happen 6 seconds after tx1 and tx1 fall out the timed window. The strange thing is that the action of the rule is executed for all the transaction in the working memory, even for tx1.

Is it supposed to work in this way?

Thanks in advance


Solution

  • The main issue is that the Engine isn't given a chance to execute pending activations and to process facts according to the current reading of the (pseudo) clock. Also, the rule will fire for each Transaction currently in working memory while you expect it to fire for the latest transaction only.

    With CEP, test or production, I recommend to run the Engine in a separate thread, calling fireUntilHalt. Then, for test or production, one can use the real clock and insert facts as they come or from a thread that pauses between insertions. And the pseudo clock can be used as well, almost without any change in the code.

    To ensure that the rule fires only for the most recent thread, change the rule to

    rule "more than 2 transaction in 5 seconds"
    when
        $transaction : Transaction( $id : id )
        not Transaction( this after $transaction )
        Number(intValue > 2) from accumulate(
            $t : Transaction() over window:time(5s),
            count($t))
    then
        System.out.println( "denied: " + $transaction );
    end