Background Jobs
Active Job + Sidekiq โ process heavy tasks asynchronously
Background Job is a pattern that separates time-consuming tasks from the HTTP request cycle to process them in a separate process.
# app/jobs/send_welcome_email_job.rb
class SendWelcomeEmailJob < ApplicationJob
queue_as :default
def perform(user)
UserMailer.welcome(user).deliver_now
end
end
# Usage
SendWelcomeEmailJob.perform_later(user) # enqueue (async)
SendWelcomeEmailJob.perform_now(user) # execute immediately (sync)
Active Job: Rails' Job abstraction layer. No code changes needed when swapping backends.
Sidekiq: Most popular Job adapter. Redis-based, multi-threaded for high throughput.
Solid Queue: New default adapter in Rails 8. DB-based, no Redis needed. However, it's process-based โ 3 default workers consume ~534MB (178MBร3), using far more memory than Sidekiq (thread-based, single process). No Redis dependency, but higher memory cost as a trade-off.
Retry:
retry_on StandardError, wait: :exponentially_back_off, attempts: 5
discard_on ActiveRecord::RecordNotFound
Key Points
rails generate job SendEmail โ create Job class in app/jobs/
Write execution logic in perform method
MyJob.perform_later(args) โ enqueue (async execution)
queue_as :high_priority โ set queue priority
retry_on / discard_on โ set retry/discard policies
config.active_job.queue_adapter = :sidekiq โ adapter configuration
Pros
- ✓ Shorter HTTP response time (better UX)
- ✓ Auto retry on failure
- ✓ Easy adapter swap (Sidekiq โ Solid Queue)
- ✓ Per-queue priority management
Cons
- ✗ Separate process management needed (Sidekiq workers)
- ✗ Complex debugging (async environment)
- ✗ Redis dependency (Sidekiq) or DB load (Solid Queue)
- ✗ Hard to guarantee order
- ✗ Solid Queue + SQLite cannot be split across machines โ SQLite is file-based with no network sharing, so Rails and Solid Queue must run on the same disk (same machine). On Fly.io etc., volumes mount to only one machine, preventing separation. PostgreSQL/Redis allow network access, enabling machine separation