Goal
You’ll understand what Active Job and background jobs solve, and be able to identify when a task genuinely belongs in a background job rather than running directly in a request.
Learn
Some tasks — sending an email, processing an image, generating a report — can take a genuinely noticeable amount of time. Running them directly inside a web request means the user’s browser sits waiting until that slow task finishes before getting any response at all.
class OrderMailerJob < ApplicationJob
queue_as :default
def perform(order)
OrderMailer.confirmation(order).deliver_now
end
end
# Enqueue it, rather than running it directly:
OrderMailerJob.perform_later(order) perform_later adds the job to a queue, returning control to the current request immediately — the actual email sending happens separately, asynchronously, handled by a background worker process, without the user’s browser waiting for it at all.
The genuinely important distinction: perform_now runs the job’s code immediately, synchronously, blocking the current request until it finishes — functionally similar to just calling the method directly. perform_later is what actually provides the real, practical benefit of background processing, deferring the work to run separately.
A reasonable guideline for identifying background job candidates: any task that’s genuinely slow (noticeably more than a fraction of a second), and doesn’t need to complete before the user can see a response, is a good candidate. Sending a confirmation email after checkout is a textbook example — the user doesn’t need to wait for the email to actually send before seeing “Order confirmed.”
Decision Task
A checkout process sends a confirmation email synchronously, taking 3 full seconds, directly inside the request that also renders “Order confirmed” to the user. Before reading on: what real problem does this create for the user’s actual experience, and how would Active Job fix it?
Show Answer
The user’s browser sits waiting for a noticeable 3 full seconds before seeing any response at all, purely because of the email sending, even though the actual order was already successfully placed. Using OrderMailerJob.perform_later(order) instead would return control to the request immediately, letting “Order confirmed” render right away, with the actual email sending happening separately in the background, invisible to the user’s wait time.
Common Mistake
Running genuinely slow tasks (like sending emails or processing images) synchronously inside a web request, when they don’t actually need to complete before the user can see a meaningful response. This directly and unnecessarily increases how long the user has to wait, when a background job would let the response return immediately while the slow work happens separately.
Practice Questions
1. Write the code that enqueues an existing job called ReportGeneratorJob to run in the background for a given report_id.
Show Answer
ReportGeneratorJob.perform_later(report_id)
2. What’s the practical difference between perform_now and perform_later?
Show Answer
perform_now runs the job immediately and synchronously, blocking the current request; perform_later enqueues it to run separately, asynchronously, letting the current request continue immediately.
3. What real user-facing benefit does perform_later provide for a task like sending a confirmation email?
Show Answer
The user sees their response (like “Order confirmed”) immediately, without waiting for the email itself to actually finish sending in the background.
4. True or False: a background job should be used for every single task in a Rails application, regardless of how fast it is.
Show Answer
False — background jobs are genuinely useful specifically for noticeably slow tasks that don’t need to complete before the user sees a response; using them for genuinely fast tasks adds unnecessary complexity with little real benefit.
5. Name one genuinely good candidate task for a background job, and explain why, using this lesson’s guideline.
Show Answer
Sending a confirmation email — it’s noticeably slow and doesn’t need to complete before the user can see a meaningful response, matching exactly the guideline this lesson describes.
Try It Yourself
Without looking back, write a basic Active Job class called ImageProcessorJob with a perform method that takes an image and calls a hypothetical process! method on it.
Show Answer
class ImageProcessorJob < ApplicationJob\n queue_as :default\n\n def perform(image)\n image.process!\n end\nend
Quick Check
1. What problem does running a slow task directly in a web request create?
Show Answer
The user’s browser waits, unresponsive, until that slow task finishes before getting any response at all.
2. What does perform_later do, compared to perform_now?
Show Answer
Enqueues the job to run separately/asynchronously, rather than running it immediately and blocking the current request.
3. What’s a good general guideline for identifying background job candidates?
Show Answer
Genuinely slow tasks that don’t need to complete before the user can see a meaningful response.
4. Give an example of a task well-suited for a background job.
Show Answer
Sending a confirmation email (or processing an image, generating a report).
5. What must an Active Job class define, containing the actual work to be performed?
Show Answer
A perform method.