Why Background Jobs
Fast recall
Quick revision
Core answer
Whether you know background jobs move slow work out of the request so the user gets a fast response, with retry/scale/scheduling.
Doing slow work (email, PDF, external API) in the controller — user waits, request may time out.
Background jobs move slow work out of the request (email, PDF, API, CSV). Fast response, retry, scale, schedule. >100ms or external -> job.
Interview-ready guide
Interview answer
A background job is work recorded for a separate worker process to perform outside the current web request. It is useful when the response does not need the finished result and the work is slow, bursty, scheduled, or worth retrying independently.
The request validates the operation, commits the important application state, and places a small job payload on a queue. A worker later reserves that payload, runs the job, and records success or raises a failure. Queue delay therefore becomes part of the feature, not an invisible implementation detail.
For example, account creation can commit the user and enqueue a welcome-email job. The HTTP response returns after durable account creation rather than waiting for the mail provider. If delivery is delayed, the account still exists and the email operation can retry without repeating registration.
Deferral creates boundaries. Enqueuing before a database transaction commits can let a worker look for data that is not visible yet; committing without reliably publishing can leave required work missing. The design may use after-commit enqueueing, an outbox, or reconciliation according to the consequence of loss.
A job may run more than once, so effects need idempotency or a unique business key. Expected business outcomes should become explicit states, while unexpected exceptions can enter retry and alerting policy. I would not enqueue password validation or a calculation the current response must return, because asynchronous work cannot satisfy that immediate contract.
Why Background Jobs
Direct Answer
A background job moves work out of the request-response path so the server can acknowledge the request without waiting for slow or independently retryable processing. Good candidates include email delivery, report generation, media processing, webhooks, and batch maintenance. Enqueuing is not completion: the application must define job status, retry and failure behaviour, idempotency, and the consistency boundary between the database change and queue publication. Work whose result is required for the current response should normally remain synchronous.
Deep Dive & Architecture
The request lifecycle ends when the server responds; the job lifecycle can still be queued, scheduled, running, retried, failed, or complete. A product that tells a user “report created” immediately after enqueueing confuses those states. “Report accepted” plus a status endpoint or notification reflects the real contract.
A queue absorbs a burst only by turning load into waiting time. Workers still need enough capacity to drain it. Queue depth, oldest-job age, runtime, success rate, and retry volume reveal whether asynchronous processing is healthy; request latency alone cannot show a blocked worker fleet.
Delivery guarantees are built from several components and failure windows. A request can commit but fail to enqueue, a process can stop during execution, and an external service can accept a call before the worker records success. Idempotency keys, database constraints, durable publication patterns, and reconciliation close different gaps.
The best job boundary names one recoverable business operation and carries references rather than a snapshot of the whole object. The worker reloads current state, decides whether work is still needed, and makes its effect safe to repeat. This keeps a delayed job meaningful after the application has changed around it.
Code Example
class RegistrationsController < ApplicationController
def create
user = User.create!(user_params)
WelcomeEmailJob.perform_later(user.id)
render json: { id: user.id, email_status: 'queued' }, status: :created
end
end
class WelcomeEmailJob < ApplicationJob
def perform(user_id)
user = User.find(user_id)
UserMailer.welcome(user).deliver_now unless user.welcome_email_sent?
end
end
Common Mistakes & Pitfalls
Doing slow work (email, PDF, external API) in the controller — user waits, request may time out.
Check your understanding
Answer these without looking back at the article.
- What does a successful enqueue guarantee compared with completed work?
- Which failure window exists between a database commit and queue publication?
- Why must a background side effect be safe when the job runs again?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.