Search code examples
droolsdrools-fusion

Drools Engine: Memory management for a high-traffic application


The purpose of this code is to monitor the flow of events of different categories, and raise different levels of alarms in different categories, based on the frequency of events of the corresponding category. The level of alarms for each category increases progressively, and only 1 Alarm object is inserted per level per category. Alarms must expire if they are old enough AND can no longer satisfy any rule. The time for each level of alarm to expire for each category is different. Also Events must expire at different times to achieve the optimum memory usage.

The automatic event life-cycle management does not work at all when declaring both Alarm and Event objects as events. If I declare Alarm as fact, objects of type Event get discarded as intended, but unsurprisingly, objects of type Alarm remain in the memory forever.

Question: How can I manage the memory properly and discard the unnecessary Alarm/Event objects? Utilizing Drools' inferred expiration is preferred; can I change my code in any way to make it work?(Like adding time constraints to the existing rules, maybe?) Adding an expires tag to the Event/Alarm types is a last resort.

Thanks in advance

declare Event
    @role(event)
end

declare Alarm
    @role(event)
end

rule "Alarm Level 1"
    when
        $e : Event()
        not (Alarm(category == $e.getCategory(), level == 1)
    then
        Alarm a = new Alarm($e.getCategory());
        a.setLevel(1);
        insert(a);
end


rule "Alarm Level 2"
    when
        $alarm : Alarm(level == 1)
        not (Alarm(category == $alarm.getCategory(), level == 2)
        Number( intValue >= 5 ) from accumulate(
            $e : Event(category == $alarm.getCategory()) over window:time( 1h ),
            count($e) )
    then
        Alarm a = new Alarm($alarm.getCategory());
        a.setLevel(2);
        insert(a);
end

rule "Alarm Level 3"
    when
        $alarm : Alarm(level == 2)
        not (Alarm(category == $alarm.getCategory(), level == 3)
        Number( intValue >= 15 ) from accumulate(
            $e : Event(category == $alarm.getCategory()) over window:time( 2h ),
            count($e) )
    then
        Alarm a = new Alarm($alarm.getCategory());
        a.setLevel(3);
        insert(a);
end

EDIT: The project's requirements are to monitor the frequency of Events and fire Alarms if necessary(described in more details above). Those Alarms can also participate in firing of a set of rules, each with their own time limit.

In other words, I need to write a rule like this:

rule "A"
    when
        $a Alarm($param : some_param, some_constraints, happened_in_last_n_secs)
        $e Event(some_param == $param, some_constraints, happened_in_last_m_secs)
    then
        do_stuff
end

Is there something like the code below in Drools?

$eventA : Event( this before[ 0s, 4m ] time.now )

Solution

  • There is no Now fact automatically provided by Drools.

    Consider creating this event and updating its time stamp whenever a rule driven by a timer with appropriate interval fires.

    Edit The automatic time-stamping by Drools must be considered as a sloppy solution. It is most certainly suitable for applications where the true time stamp isn't paramount or not available. Otherwise, an event's time stamp should be determined where the event is created and become one of the event's properties. You can access this field like any other attribute and compare its value using temporal operators.