Tuesday, February 16, 2010

ActiveMQ 5.4: JMS Timer and CRON Scheduler

I've added a persistent scheduler engine to ActiveMQ, so that messages that are scheduled for delivery will always survive restarts. The scheduling of some message in the future can be useful - but deciding  a scheduling syntax that is flexible, but can also fit into Message header properties is a little tricky.  I've decided the best approach is to use a combination of different concepts - simple delay, repeats and CRON.

There are a few choices of around scheduling messages to deliver in the future(inspiration from java.util.Timer)  - a simple delay - this one will deliver the message in a minute:

long time = 60 * 1000;
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); 

Delivery at a fixed rate - this example will delivery 10 messages, waiting 10 seconds between each message - note the repeat count is 9 (9 + first one = 10).
long delay = 30 * 1000;
long period = 10 * 1000;
int repeat = 10;
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay);
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, period);
message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, COUNT repeat);

For more advanced messaging you can use CRON scheduling - this one will deliver a message at 2AM on the 12 day of every month:

message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "0 2 12 * *");

You can combine delays and repeats with CRON. For example, you may wish to send 10 messages, every 30 minutes, with a delay of 10 seconds between each one.

message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "30 * * * *");
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, 10*1000);
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 10*1000);
message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, 9);

As I quickly realised whilst testing -  having a persistent message scheduler that survives re-starts really needs management support - so that you can delete those pesky jobs that you accidentally scheduled ;). So there's JMX support - and the ActiveMQ Web Console has been updated too:


dkfn said...

This is awesomely useful. Funny you should mention needing a UI to cancel the jobs. Having some programmatic way to do that will probably become necessary (even cancellation of one off jobs).

Anonymous said...

Rob, I have been trying to figure out how to use this new feature with Spring Integration but I can't seem to get it to work. Can you provide an example of how to use this feature within Spring Integration.


Anonymous said...

Is there any way to check if the message has been already scheduled (to avoid duplicates)?

Rob Davies said...

Messages to be scheduled have one of the following properties set - this is checked by the SchedulerBroker (part of the ActiveMQ Broker):


When they are moved from the ScheduleStore to be processed as normal by the broker, these properties are removed.