Sidekiq: Background Jobs in Ruby

· 4 min read · Updated March 8, 2026 · intermediate
sidekiq background-jobs redis ruby performance

Sidekiq is a Ruby background job processor that allows you to move time-consuming tasks out of your request-response cycle. Instead of making users wait for tasks like sending emails, processing images, or calling external APIs, you queue them for background processing. This guide covers everything you need to know to integrate Sidekiq into your Ruby applications.

Why Background Jobs Matter

Web applications often need to perform tasks that take seconds or even minutes to complete. If you handle these synchronously, users experience slow response times and your server threads get blocked. Background jobs solve this by moving these tasks to a separate process that runs independently of the web request.

Sidekiq uses Redis as a message broker to store job data. It processes jobs using worker threads instead of forked processes, making it incredibly efficient. A single Sidekiq process can handle hundreds of jobs per second with minimal memory overhead.

Installing Sidekiq

Add Sidekiq to your Gemfile:

gem 'sidekiq'

Then install the gem:

bundle install

Sidekiq requires Redis to be running. You can start Redis locally or use a hosted service:

redis-server

Creating Your First Worker

Workers are Ruby classes that define the work to be done in the background. Each worker has a perform method that Sidekiq calls when processing the job:

class HardWorker
  include Sidekiq::Worker

  def perform(id, name)
    # Do something expensive
    puts "Processing #{name} with ID #{id}"
    sleep(5)  # Simulate expensive operation
  end
end

The include Sidekiq::Worker module adds the perform_async class method to your worker. This method enqueues the job for background processing:

# Enqueue a job to be processed asynchronously
HardWorker.perform_async(42, "Alice")

# You can also pass additional arguments
HardWorker.perform_async(42, "Alice", { priority: "high" })

Job Execution Options

Sidekiq provides several options to control how jobs execute. You can schedule jobs to run in the future or repeat them at intervals:

# Execute in 10 minutes from now
HardWorker.perform_in(600, 42, "Bob")

# Execute at a specific time
HardWorker.perform_at(1.hour.from_now, 42, "Charlie")

# Repeat every hour, starting now
HardWorker.perform_async(42, "Diana")
# Then use sidekiq-scheduler or sidekiq-cron for recurring jobs

Configuring Sidekiq

Sidekiq configuration goes in an initializer. Here’s a typical configuration for a Rails application:

# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.redis = {
    url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/1'),
    size: ENV.fetch('SIDEKIQ_CONCURRENCY', 25).to_i
  }
end

Sidekiq.configure_client do |config|
  config.redis = {
    url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/1')
  }
end

The concurrency setting controls how many worker threads run simultaneously. Each thread can process one job at a time. Start with 25 threads and adjust based on your workload and server resources.

Queue Management

Sidekiq supports multiple queues with different priorities. By default, jobs go to the “default” queue, but you can specify different queues:

class EmailWorker
  include Sidekiq::Worker
  sidekiq_options queue: 'mailers'

  def perform(user_id, subject, body)
    # Send email
  end
end

Configure queue priorities in your Sidekiq configuration:

# config/sidekiq.yml
:concurrency: 25
:queues:
  - [critical, 3]
  - [default, 2]
  - [mailers, 1]
  - [low, 1]

The numbers indicate priority weight—higher numbers mean higher priority. Jobs in the “critical” queue get processed before “default”, which gets processed before “low”.

Error Handling and Retries

Sidekiq automatically retries failed jobs with exponential backoff. Configure retry options in your worker:

class SensitiveWorker
  include Sidekiq::Worker
  sidekiq_options retry: 5  # Maximum 5 retries
  sidekiq_retry_in do |count|
    10 * (count + 1)  # 10s, 20s, 30s, 40s, 50s
  end

  def perform(data)
    # Work that might fail
  end
end

For jobs that should never retry, use sidekiq_options retry: false:

class NoRetryWorker
  include Sidekiq::Worker
  sidekiq_options retry: false

  def perform(id)
    # Don't retry on failure
  end
end

You can also move failed jobs to a dead queue after all retries are exhausted using the dead queue feature.

Testing Workers

Testing Sidekiq workers requires a different approach than regular unit tests. Use the sidekiq/testing helper to process jobs synchronously:

require 'sidekiq/testing'

describe HardWorker do
  it 'performs the job' do
    HardWorker.perform_async(42, "test")
    
    # Process jobs synchronously
    HardWorker.drain
    
    # Assert the job ran
    expect(HardWorker.jobs.size).to eq(0)
  end
end

For integration tests that actually run jobs asynchronously, use Sidekiq::Testing.inline!:

Sidekiq::Testing.inline!

Starting Sidekiq

Start the Sidekiq process from your application root:

bundle exec sidekiq -C config/sidekiq.yml

In production, use a process manager like systemd or Supervisor to keep Sidekiq running:

bundle exec sidekiq -d -P /tmp/sidekiq.pid -C config/sidekiq.yml

The -d flag daemonizes the process and -P specifies the PID file location.

When to Use Sidekiq

Sidekiq excels when you need to process many jobs quickly, handle long-running tasks without blocking web requests, or scale background processing across multiple workers. It’s particularly well-suited for sending emails, processing file uploads, calling third-party APIs, generating reports, and scheduled maintenance tasks.

When Not to Use Sidekiq

Avoid Sidekiq for very simple tasks that complete in milliseconds—you’ll add unnecessary complexity. If you only need to run jobs occasionally, a simpler solution might suffice. Also, Sidekiq requires Redis, so you need to budget for that infrastructure overhead.