Four things you should always move into background jobs

Rails is built to serve web-applications. It is 95% focussed on responding to incoming HTTP requests, doing something with that request and then returning a HTTP response.

And it makes it really easy to do this. And make your application respond very quickly.

However, if you have a slow response to an incoming request, it can cause bottlenecks in your application and it stops responding to other users.

The solution to this is to move your work into background jobs. A while back, this meant choosing a type of queue, installing the gem and coding to that gem’s API. But now, Rails has standardised this, with its Active Job component.

But what sort of things should go in the background?

Sending emails

The obvious candidate is sending emails. If your email sending service responds slowly, it will obviously slow your response down. If you have to send multiple emails (one to each recipient on a message thread, for example) then each tiny slowdown adds up to one huge slowdown.

Luckily, ActiveJob works really well with ActionMailer so you’ve got no excuse for tying up your web-server with email deliveries.

Deleting records with dependencies

If you have an ActiveRecord model that uses has_many associations, you should, in most cases, specify the “dependent: :destroy” option. This means that when your record is destroyed, it goes through the association and destroys the associated records as well. This means you aren’t left with “orphaned” records that point to a non-existent master record.

But imagine your dependent models also use has_many associations. And their dependents have their own dependents.

Suddenly, what looked like a simple delete operation ends up cascading down through several tables, deleting a whole host of records.

If you find this happening, it’s best to move the deletion into a background job – in your controller, make sure you warn the user (via a flash message) that the deletions will take place shortly, so they aren’t confused by the sight of a record they thought they had removed.

Generating PDFs

I tend to use PDFKit to generate PDFs in my applications. It uses the wkhtmltopdf tool to connect to a URL in my application, read the HTML and CSS and convert that into a PDF – meaning I can use the same HTML/CSS skills that I use for building pages to build reports and other downloads.

But it’s a slow process – it can take a good few seconds to invoke wkhtmltopdf and wait for it to download the PDF, before I can send it back to the user.

So instead, I ask the user to enter their email address, then generate the PDF in the background and email it to them. Keeping the main part of the application clear for dealing with immediate requests.

Calling External APIs

Lastly, every time you need to call out to an external API, see if you can put that into a background task. Because it’s external you can never be certain how fast it’s going to respond. Or even tell if the service is running.

Most job queue backends provide automatic retries (certainly Delayed Job, Sidekiq and Resque do). This means if a job fails, it will try again in a couple of seconds. If it fails again, it will try again in a couple of minutes. And so on, up to a maximum number of retries. So if your external service is running slow, or has gone down, your system will still fetch or update its required data … eventually.

Active Job makes it simple to make your application more responsive. It takes a bit more setup in deployment (you need to add in at least one background task to process the jobs) but it’s most definitely worth it – I never release apps without one.

Do you know what to do but not how it works?

Ever wanted to understand why Rails views work the way that they do? Why variables from your controllers are visible inside your views?

Sign up below to get a free 5 part email course on how Ruby on Rails view rendering works and gain a deep understanding of the Rails magic.

We will send you the course, plus the occasional update from this web-site. But no spam, we promise, and it's easy to unsubscribe