Wednesday, May 12, 2010

Recording of Grails / Terracotta webinar

In case you missed it and in case you're interested, Terracotta has posted a recording of the webinar that Mike Allen and I held a couple weeks ago. You can catch it in all of its glory (or lack thereof :) at http://bit.ly/scaling_grails.

During the demo I mentioned a blog post coming to the GQuick blog where we would add Quartz scheduling to TekDays (the sample app from GQuick), well that post ended up here instead.

Once again I'd like to thank the folks at Terracotta for their cool technology and for their support of the Grails community.

Tuesday, May 4, 2010

Quartz and Grails: A Quick-Start Guide

Terracotta's Quartz scheduler has always played a key role in Grails development. Originally it was built into the framework; now it is a core plugin. Quartz allows us to have code executed at regular intervals. This a great way to have batch processes or system checks performed at off hours.


The Quartz plugin provides three different mechanisms (triggers) to determine the timing of job execution: Simple, Cron, and Custom. With a simple trigger, we can set the amount of time to wait before initial job execution, an interval to wait between repeated executions, and the number of times the job should be executed. The cron trigger also allows us to set a start delay. Then it takes a cron expression, which we can use to set a wide range of schedules. With a custom trigger – well, you can use your imagination.


In our TekDays application, we have lists of tasks that need to be done to organize a technical event. These tasks have due dates, but we currently have no way of reminding event organizers and volunteers when they have tasks that are overdue. That's where Quartz comes in. In this post, we'll create a Quartz job to check for overdue tasks and send a reminder email to the person assigned to that task.


First, we'll install the Quartz plugin:



> grails install-plugin quartz

The plugin provides us with a new Grails script, create-job. We'll use this script to create our TaskReminderJob.



> grails create-job TaskReminder

The create-job script will create a stubbed out TaskReminderJob.groovy that looks like this:



class TaskReminderJob {
def timeout = 5000l // execute job once in 5 seconds

def execute() {
// execute task
}
}

We'll replace the timeout property with a triggers closure in a moment, but first let's look at the execute method. This method will be called at the intervals that we determine with the triggers. We can put any code we want in this method, but the most common practice, and the one we'll follow, is to call a method of a service class.


For triggering the call to our service method we'll use the cron expression: "0 0 2 ? * MON-FRI", which will execute every weekday at 2:00AM. This is how our new TaskReminderJob looks:



class TaskReminderJob {
def taskService
static triggers = {
cron name: 'cronTrigger', cronExpression: "0 0 2 ? * MON-FRI"
}

def execute() {
taskService.sendTaskReminders()
log.info("Task reminders sent on ${new Date()}")
}
}

Now we need to add the sendTaskReminders() method to our TaskService. This method will use the Mail plugin (which you can find more about at http://grails.org/plugin/mail), so we'll add that to TaskService too. Something like this:



class TaskService {
def mailService

//...

def sendTaskReminders(){
def tasks = Task.findAllByDueDateLessThan(new Date())
tasks.each{task ->
def recipient
if (task.assignedTo)
recipient task.assignedTo.email
else
task.event.organizer.email

mailService.sendMail {
to recipient
from "admin@tekdays.com"
subject "Task Reminder"
body """The following task is overdue:
${task.title}"""
}
}
}
}

That's all there is to it. We now have the confidence of knowing that event organizers and volunteers will be kept informed of the tasks they need to do. And based on the experience of some people I know who recently put on a tech conference, this is important.


Now, something that in days past might have required us developers to climb tall mountains to make supplication to sysadmins wearing robes and conical hats has been made almost trivial by Quartz and the Quartz plugin. I, for one, am impressed and grateful. (I'm getting way too old for mountain climbing.)


But wait (as they say) – there's more. As TekDays gets more and more traffic (which we know will happen with all the new and exciting technologies coming out these days), we will want to take advantage of the power of Terracotta and cluster our Quartz jobs. To do this, we just need to create the property file: grails-app/conf/quartz.properties. Then enter the following values in this file:



org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore
org.quartz.jobStore.tcConfigUrl = localhost:9510
org.quartz.scheduler.instanceName = TekDaysScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.jmx.export = true

Finally, we'll copy quartz-terracotta-1.1.0.jar in our lib folder. The quartz-terracotta jar comes in the Terracotta download, which can be found at http://www.terracotta.org/dl/oss-download-catalog.


Now, if we've clustered our TekDays application as described in an earlier post, our scheduled jobs will be spread out across all the nodes. Not too shabby.


There is still some room for improvement in the Grails / Terracotta integration story, but I continue to be amazed at just how low the barrier of entry is to these powerful products.