Over the past few years, one of my largest annoyances as a Rails developer was sending email. Why? Because it’s slow. The client often has to wait 5-6 seconds for a response, which is unacceptably long, be it a normal page reload or even AJAX.
To combat this issue, one of the most common solutions was to use a background processor. You would send your mail to the job processor, it would queue it up, and send them out later, while your application can return a response right away.
I stopped using this method 2 years ago. Background job processors in Ruby were a bit of a mess. You would have to watch them, monitor them, code around them, and I found it to be just to much overhead for simply sending mail. The instability of long-running Ruby processes meant that running this queue was a bit of a job on it’s own, requiring babysitting or your mail wouldn’t be going out.
Instead, I found tra’s excellent spawn project, letting me fork calls to
ActionMailer to be executed immediately. Sure, sending a TON of mail at once instead of queueing it could turn into a theoretical problem, but I’ve never encountered it. After we migrated our Rails deployments to Ruby 1.9, I modified the spawn library to be compatible with the new version of Ruby, and have been copying it into vendor/plugins for every new project I start. It’s one of the few tools that has stayed with me from project to project for such a long period of time.
I was excited to hear that similar functionality would be included in the next Rails release. Up and coming in Rails 4.0 is a new Queuing system, which on the surface provides a DSL very similar to how I use spawn. This makes it extremely easy to run asynchronous code ‘out-of-the-box’, without having to depend on external libraries, processes, or daemons. On top of this new Queue, a dedicated Asynchronous ActionMailer is being released to specifically address sending mail asynchronously.
While I love the idea, I wanted to address one aspect of it’s implementation. When you are passing variables from your code to the mailer, you “should” not pass objects, instead you should pass something that can uniquely identify the object to be picked up again on the other side (for example, an
id to be used with
I can’t decide if this is good or bad design. On one hand, I can’t help but think the additional code is just a needless repetition. You are quite literally repeating yourself, calling the same (or similar) code to fetch from the database an object you already have. Additionally, this will keep one implementation incompatible with the next. You can’t just ‘switch on’ asynchronous ActionMailer without refactoring your code.
Is it bad to be passing mutable objects around between different threads? In theory yes, but in practice, I have yet to be bitten by a problem because of this. Be careful with your code.
– Not passing around mutable objects to separate threads
– Not 1:1 compatible with ‘synchronous’ ActionMailer code
– Additional database calls
– Not DRY
So there we have it. No more background job-queue overhead to send mail or do simple asynchronous tasks. Just one of the features that’s going to make Rails even better in 4.0. Let us know what you think in the comments.