Choosing a Background Job Processor for Ruby on Rails: Sidekiq, Delayed Job, or Resque
Compare Sidekiq, Delayed Job, and Resque for Rails background work, see trade‑offs, and get a concrete Sidekiq setup example.
28 Mar 2026, 16:17 UTC

Decision and Constraints
You need to add asynchronous processing to a Ruby on Rails application. The choice must satisfy:
- Automatic retries with exponential backoff.
- Visibility into queues, processed jobs, and failures.
- Compatibility with Ruby ≥ 2.7 and Rails ≥ 6.0.
- Minimal operational overhead given your existing deployment infrastructure.
Three mature libraries meet these basics: Sidekiq, Delayed Job, and Resque. The following guide compares them, outlines trade‑offs, and walks through a concrete Sidekiq implementation you can adapt to your environment.
Comparison of Supported Options
| Feature | Sidekiq | Delayed Job | Resque |
|---|---|---|---|
| Backend | Redis | ActiveRecord (database) | Redis |
| Retry mechanism | Built‑in, configurable | Built‑in, configurable | Built‑in, configurable |
| Monitoring | Web UI, Prometheus metrics | Simple admin view | Web UI (via resque‑web) |
| Typical latency | Low (sub‑second) | Higher (DB polling) | Low (sub‑second) |
| Operational overhead | Requires Redis instance | Uses existing DB | Requires Redis |
| Community & maturity | Very active, widely used | Stable, less active | Active but smaller |
Trade‑offs
Sidekiq delivers the highest throughput and lowest latency because jobs are pushed to Redis and processed by a multi‑threaded pool. The downside is the need to run and maintain a Redis server; if Redis is not persisted, jobs can be lost on a restart unless you enable AOF or RDB snapshots.
Delayed Job avoids any extra service by storing jobs in the same database used by your Rails app. This simplifies initial setup but introduces database load from frequent polling of the delayed_jobs table. Under high volume, latency can increase and the polling may affect overall DB performance.
Resque also uses Redis, offering reliability similar to Sidekiq, but its ecosystem is smaller and the default web UI is less feature‑rich. Failed jobs remain in the “failed” set until you manually retry or prune them, which requires extra monitoring.
If you already operate Redis for caching or other services, Sidekiq is often the best fit for performance‑critical workloads. If you prefer to keep the stack minimal and can tolerate modest latency, Delayed Job works well for low‑to‑moderate job volumes. Resque sits in the middle when you want Redis‑backed durability but desire a simpler UI than Sidekiq’s.
Concrete Implementation: Setting Up Sidekiq
The steps below assume a Rails 6.0+ app with Bundler and access to an environment variable REDIS_URL pointing to a persistent Redis instance.
- Add the gem to your
Gemfile:gem 'sidekiq' - Install dependencies:
bundle install - Create an initializer to configure the Redis connection (e.g.,
config/initializers/sidekiq.rb):Sidekiq.configure_server do |config| config.redis = { url: ENV.fetch('REDIS_URL') } end Sidekiq.configure_client do |config| config.redis = { url: ENV.fetch('REDIS_URL') } end - Define a worker class. Place it under
app/workers(e.g.,app/workers/hard_worker.rb):class HardWorker include Sidekiq::Worker def perform(name, count) # Replace with real work; logging is shown for verification Rails.logger.info "HardWorker performing for #{name} with count #{count}" end end - Enqueue the job from anywhere in your code (controller, model, console, etc.):
HardWorker.perform_async('Bob', 5) - Start the Sidekiq processor in a separate terminal or as part of your deployment:
bundle exec sidekiq
Validation Steps
After enqueuing a job and starting Sidekiq, you can verify successful execution:
- Check the Sidekiq web UI (by default mounted at
/sidekiq) – the job should appear under the “Processed” tab and the “Failed” count should remain zero. - Inspect your application logs (e.g.,
log/development.logor stdout in production) for the line generated by the worker’sperformmethod. - In the Rails console, you can also query the Redis queue size via
Sidekiq::Queue.new.sizeto confirm the job was removed from the queue after processing.
If you prefer to validate with Delayed Job instead, the analogous steps are:
- Add
gem 'delayed_job_active_record'and runrails generate delayed_job:active_recordfollowed byrails db:migrate. - Create a job class inheriting from
ActiveJob::Baseor useDelayed::Job.enqueuewith a custom class. - Start the worker with
rake jobs:work. - Confirm that a row inserted into the
delayed_jobstable disappears after processing and that any logging inside the job’sperformmethod appears.
Limitations and Practical Checks
Sidekiq: Ensure Redis persistence is configured (AOF or RDB) to avoid job loss on restart. Monitor Redis memory usage; a backlog of jobs can cause Redis to swell. Use the Sidekiq UI to track enqueued, processed, and failed counts, and set up alerts if the failed count rises.
Delayed Job: Tune the polling interval (Delayed::Worker.sleep_delay) to balance latency against DB load. For high‑throughput scenarios, consider switching to a queue‑based backend to eliminate polling overhead.
Resque: Periodically inspect the “failed” queue via the Resque web UI or the Resque::Failure API, and implement a retry strategy (e.g., using the resque-retry plugin) to avoid manual intervention.
Regardless of the library you choose, verify that your deployment process (e.g., Docker, Heroku, Kubernetes) starts the worker processes alongside the web server and that they shut down gracefully to prevent orphaned jobs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.