Wednesday, December 02, 2009

Cron and Interval based timers for rule firing and re-firing

At ORF I did a presentation on ideas I'd like to do to improve our language. You can see that presentation here:
"Drools "Where do we go from here" - presented at ORF09"

In this presentation I discussed the idea of "cron" based rules. Drools has supported the "duration" attribute for a long time now. When a rule is activated it does not fire straight away, instead it is scheduled to fire based on the given duration. If the rule is still true on or after that duration lapses it fires, otherwise if it becomes false before the duration lapses it is cancelled and unscheduled.

The problem here is the duration is a single value and the rule fires just once. This is useful, but somewhat limited. Instead wouldn't it better if we could support various time based semantics for rule firing and re-firing (if the rule is still true).

While not exposed to the user I created pluggable Time semantics. This introduces the Timer interface:
interface Timer {
/**
* Creates a Trigger for this Timer, based on the provided current timestamp.
*/
Trigger createTrigger(long timestamp);
}
The Trigger interface already existed as part of our unified clock and scheduling framework in Drools. Trigger tells the scheduler the next date to trigger the current job on. If we have multiple Timer semantics, not just duration, each Timer must be responsible for providing it's own Trigger to handle the execution of those semantics.

The 'duration' keyword has now been renamed to 'timer', although backwards compatability has been kept. We now support two different timers 'cron' and 'interval'. The 'timer' keyword takes a colon delimited prefix, using 'cron:' and 'int:' respectively. If no protocol is given, it assumes 'int'.

We use the standard cron syntax (thank you quartz), with added support for seconds. And interval has two parameters and obeys the JDK Timer semantics of delay and period. Where delay is the initial delay and period is the period of time between each iteration.

So now we can do the following which will send an SMS to a give mobile number every 0, 15, 30 and 45 minutes past each hour, while the alarm remains true:
rule "Send SMS every 15 minutes"
timer (cron:* 0/15 * * * ?)
when
$a : Alarm( on == true )
then
exitPoint[ "sms" ].insert( new Sms( $a.mobileNumber, "The alarm is still on" );
end

5 comments:

  1. Mark, this is a GREAT feature! Is this now available on the trunk?

    ReplyDelete
  2. Yes this is working in trunk now. I still need to add calendaring support, which specifies the times for when a trigger may fire. I'll genericise that further so actually the Calendar specifies when a rule itself may fire.

    This will be integrated with Flow, so that we can use rules and their timers to start processes. What I need now is a visual cron editor for eclipse :)

    ReplyDelete
  3. For bonus points, you can have your application start remotely when you press Visual Studio's green triangle button, just like normal. Under the Debug settings for the Project, you need to check "Use remote machine", and then under Start Options you need to launch the external program using a path that is local to the remote machine.

    ReplyDelete
  4. Could I check out a TAG rather trunk to get this Timing feature ?

    ReplyDelete
  5. But we will put out M2 this week with the feature in.

    Mark

    ReplyDelete