0
votes

I've had to create pairs of rules to retract my events. It seems they don't expire. I had wanted one-and-done events. You can see below, they use the default duration, zero.

So for example, if I exclude the retraction rules and then insert the RemoveConnectionEvent first and then insert the CreateConnectionEvent, the RemoveConnection rule will still fire. (Using an agenda listener in my unit tests)

My expectation of an event was that RemoveConnectionEvent would be ignored, it would not do anything if its conditions were not met immediately. I did not expect it to hang around and trigger the RemoveConnection rule once that rules conditions were met when the NewConnection rule responded to the CreateConnectionEvent.

To get my rules to behave as I expected, I created RetractedCreation, RetractedRemoval, and RetractedUpdate. This seems to be a hack. I am imagining a declared my events wrong.

Any ideas?

ps This was a pretty good Q&A but I am not using windows. It might infer that perhaps my hack is an 'explicit expiration policy'.

Test Event expiration in Drools Fusion CEPTest Event Expiration

Here is my rule.

package com.xxx
import com.xxx.ConnectedDevice
import com.xxx.RemoveConnectionEvent
import com.xxx.CreateConnectionEvent
import com.xxx.UpdateConnectionEvent

declare CreateConnectionEvent @role( event ) end
declare UpdateConnectionEvent @role( event ) end
declare RemoveConnectionEvent @role( event ) end

rule NewConnection
    when
        $connection : CreateConnectionEvent($newChannel : streamId)
        not ConnectedDevice( streamId == $newChannel )
    then
        insert( new ConnectedDevice($newChannel) );
end

rule RetractedCreation
    when
        $creationEvent : CreateConnectionEvent($newChannel : streamId)
        exists ConnectedDevice(streamId == $newChannel)
    then
        retract($creationEvent)
end

rule RemoveConnection
    when
        $remove : RemoveConnectionEvent($newChannel : streamId)
        $connection : ConnectedDevice( streamId == $newChannel )
    then
        retract( $connection );
end

rule RetractedRemoval
    when
        $removalEvent : RemoveConnectionEvent($newChannel : streamId)
        not ConnectedDevice(streamId == $newChannel)
    then
        retract($removalEvent)
end

rule UpdateConnection
    when
        $connectionUpdate : UpdateConnectionEvent($newChannel : streamId) 
        $connection : ConnectedDevice( streamId == $newChannel )
    then
    $connection.setLastMessage();
end

rule RetractedUpdate
    when
        $removalEvent : UpdateConnectionEvent($newChannel : streamId)
        not ConnectedDevice(streamId == $newChannel)
    then
        retract($removalEvent)
end
1
Hi I'm the op of the Q&A sliding window you linked. I think @laune 's answer below is very complete as always, just FYI, as you don't mention how session clock is managed in your code, this other reproducer which is not related to sliding window but to session clock sync and automatic event expiration issues.jboss.org/browse/DROOLS-158 might have analogies to your use case. Hope this helps as well, Ciaotarilabs

1 Answers

2
votes

This automatic expiry is a rather elusive feature. There's no concise definition when it'll work, and what needs to be done to make it work.

In your apparently simple case where you don't use temporal operators and expect that events are to be retracted after they have matched one rule I'd adopt the following strategy without wasting another thought on "inferred expiration" and "managed lifecycle".

Maybe you have a common (abstract) base class for your events; otherwise create a marker interface and attach it to all events. Let's call this type Event. Then, a single rule

rule "retract event"
salience -999999
when
    $e: Event()
then
    retract( $e );
end

will take care for all (Create, Update, Remove) events.

Edit You may also use the explicit setting for event expiry.

declare CreateConnectionEvent
    @role( event )
    @expires(0ms)
end

Make sure to use

KieBaseConfiguration config = ks.newKieBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
KieBase kieBase = kieContainer.newKieBase( config );

when creating the KieBase. I also recommend to "let the time pass", i.e., advance a pseudo clock or let the thread running a fireUntilHalt for a jiffy or two after fact insertion.