Sending emails in the background with cron and rake
Many web applications have to run periodic tasks and it’s really important to decouple these tasks from the clients request thread. One well-proven way to manage these is to use cron to execute the tasks. I had to do this recently to send reminder emails to authors in StatusHub and thought I’d share how easy it was.
First, create a rake task to provide an easy interface to the tasks. This makes it easy to test them out or manually run them. I created a file in lib/tasks called cron.rake:
namespace :cron do
desc "Send email reminders to all authors on upcoming and overdue reports"
task :send_reminders => :environment do
Report.send_reminders
end
end
Here, Report is one of my models and send_reminders is a class method on that:
def self.send_reminders
Report.due_drafts.find_each do |report|
Mailer.deliver_report_due report
end
end
The Mailer model is a subclass of ActionMailer::Base and has methods for each type of message you want to send. This one looks like:
def report_due(report)
recipients report.author.email
from "StatusHub<support@statushub.com>"
subject "Your report entitled '#{report.title}' is #{report.overdue? ? 'overdue' : 'due'}"
sent_on Time.now
content_type "text/plain"
body :report => report, :url => design_report_url(report, :host => report.author.account.host)
end
Calling Mailer.deliver_report_due invokes the report_due method and then renders report_due.html.erb into the body of the email. You can now test the task with:
$ rake cron:send_reminders
On the production server, the job can now be automated by adding the following like to your crontab (edit with crontab -e):
00 04 * * * cd /app/statushub/current && /usr/bin/rake RAILS_ENV=production cron:send_reminders