In this recipe we will learn how to schedule message delivery in ActiveMQ.
For this recipe, we will use the example code in the message-scheduling
project to show how you can schedule a message for later delivery. The default ActiveMQ configuration file doesn't turn on the message scheduler service. So, you will need to edit the activemq.xml
file in the conf
directory where you installed your broker and add the schedulerSupport="true"
value to the broker
XML tag, it should look something like this:
To run the sample for this recipe, you will need to perform the following steps:
Open a terminal and start a broker.
Open a second terminal, change to the directory where the message-scheduling
example is located, and run it by typing mvn compile exec:java
.
In the terminal where you started the scheduling example, you will see output like the following, indicating that the application has scheduled a message. After a few seconds, the broker will begin to send the scheduled message back to the application.
Scheduling a message in ActiveMQ is quite simple. There are no new JMS APIs to learn, and everything is done using the tools we've already learned in the previous recipes in this book. Let's first take a look at the code for the example we just executed, and then we'll walk through how it works:
In this example, we want to schedule a type of wake-up-call message to be delivered after a 20 second delay and then have it delivered again every ten seconds, nine more times. To schedule the message for delivery, we simply create the message and add the appropriate headers to it that the broker will use to apply the schedule. The destination that we send the scheduled message to is the one that the broker will use to later deliver the message.
Our sample application uses the predefined message header values in the ScheduledMessage
utility class provided in the ActiveMQ Client JAR; however, these are just string values, so you don't absolutely need to import that class into your code. The available header values for scheduled messages are shown in the following table:
The CRON-based scheduler field can be used to do more complicated scheduling than can be done with the other fields. Let's say you want to schedule a message for delivery once an hour; you can do so using code similar to the following:
We can get even more elaborate by combining the CRON settings and the other settings for delay repeat and period. The CRON entry takes precedence over the other values. For instance, if we have a message that should be delivered 10 times at the start of every hour and we wanted a 1 second delay between each message, we could do so using the following code:
Scheduled messages can be useful in a number of different scenarios; here, we use the message as a trigger to shut down our sample application after a predefined number of messages have been received, but there are plenty of other uses for this functionality. Imagine, for instance, a scheduled message that fires once a day to trigger your application to do some cleanup job that purges daily logs or to trigger some other batch processing type jobs.
It's great that we can schedule messages for later delivery, but what happens if we want to later cancel a scheduled message or find out what the current set of scheduled messages is? Fortunately, these sorts of management activities can easily be accomplished right in your Java code. You could also use some external tools, such as JMX or the ActiveMQ Broker's web console, but these are outside the scope of this book.
Managing scheduled messages on the broker generally consists of creating a standard MessageConsumer
instance and sending a control message to a predefined topic destination on the broker named ActiveMQ.Scheduler.Management. For actions that require the broker to send back responses, we make use of the JMSReplyTo
message property just as we did in the previous recipe that talked about request/response messaging. Let's take a look now at code that instructs the broker to send us all the currently scheduled messages:
As you can see from the code, the way we browse the scheduled message looks a lot like the request/response pattern. The message we send to the broker needs to indicate what action the message scheduler is being asked to perform; we do that by specifying the AMQ_SCHEDULER_ACTION_BROWSE
option for the AMQ_SCHEDULER_ACTION
message header. The broker fires them all to our supplied JMSReplyTo
destination, and we just use a normal MessageConsumer
object to read them.
Now that we've seen how to browse the messages that are scheduled for delivery, let's take a look at how to manage the scheduled messages that you've browsed. Each scheduled Message that is sent to your consumer contains a Job ID that can be used to remove that message from the scheduler using the same management destination that you used to request the browse action, the following is an example of that:
Here, we create a new message instance and set the scheduler action AMQ_SCHEDULER_ACTION_REMOVE
to indicate we are sending a remove request. Then, we tag the request with the Job ID for a scheduled message by querying the message for its AMQ_SCHEDULED_ID
message property.
If we want to remove some scheduled messages but don't want to browse them, just to find the ones we're interested in, we can do so using the remove option we just saw. But, instead of specifying a Job ID, we can give the broker a time window in which to operate. The Following is an example that shows a remove operation requested for all scheduled messages in the next hour:
Lastly, we could just remove all scheduled messages from the broker if we needed to; we do this with a single message sent to the management destination with the scheduler action of AMQ_SCHEDULER_ACTION_REMOVEALL
set.
As you can see, you don't absolutely need any external tools to manage the scheduled messages on the broker. You can implement management write in your application using standard JMS API calls.