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
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.