zerosum dirt(nap)

evolution through a series of accidents

zerosum dirt(nap)

Resque Mailer

January 09, 2010 by nap · Comments

We've been making heavy use of Chris Wanstrath's Resque library in my latest project. Resque is a Redis-based background job system that Chris built for GitHub. It's easy to use, especially if you're already leveraging Redis in other parts of your infrastructure, and also has a nice Sinatra front-end for monitoring job status.

Anyway, Resque jobs are just Ruby classes that respond to the special perform method. They're placed on a queue — you can place different jobs on different queues — and later, a worker polls the queue, pops the jobs off and performs the task.

We have a number of different asynchronous jobs happening in Mogo, many of which are domain-specific. But one thing we're doing that's very common is using the background system to process mail delivery asynchronously. Because synchronous mail delivery is for jerks.

Outgoing mail in a Rails app is generally handled by ActionMailer, which expects you to implement message delivery types as class methods on an ActionMailer "model" (a butchering of the term). So a typical mailer might look like this:

class Notifications < ActionMailer::Base

  def signup(user_id, sent_at = Time.now)
    @user = User.find(user_id)

    subject    'Welcome to Mogo'
    recipients @user.email
    from       'Mogoterra <noreply@mogoterra.com>'
    sent_on    sent_at
  end

end

Then, to send a signup message, you use the following method call from somewhere else in your codebase:

Notifications.deliver_signup(@user.id)

So this all works good but it's synchronous. You'd like to be able to background these tasks and use Resque. But you don't really want to mess around with the mailer implementation. Right? Me too.

So ResqueMailer does just that.

Following in the footsteps of DelayedJobMailer, ResqueMailer allows you to shift processing of your existing mailers to an async Resque worker without doing pretty much anything. Just install the gem in your Rails project (via Gemcutter) and then mix the Resque::Mailer module into your mailer.

class Notifications < ActionMailer::Base
  include Resque::Mailer

  # ...
end

You'll need to restart your Resque workers and make sure at least one of them is working on the special mailer queue (or * for all queues). Now when you call MyMailer.deliver_signup, the task will be placed on the mailer queue and processed by the first qualifying worker.

It's always nice when a tiny amount of code makes a task transparent. Check out the project page on GitHub for more information.

blog comments powered by Disqus