Salta ai contenuti

Sidekiq Cheat Sheet

Overview

Sidekiq is a full-featured background job processing framework for Ruby that uses threads to handle many jobs simultaneously in the same process. It is backed by Redis for job storage and provides reliable, efficient background processing with a clean API and powerful web UI for monitoring.

Sidekiq supports job retries with exponential backoff, scheduled jobs, job batches, rate limiting, unique jobs, and middleware for cross-cutting concerns. It integrates seamlessly with Ruby on Rails and can process thousands of jobs per second with minimal memory overhead compared to process-based alternatives.

Installation

Gemfile

# Gemfile
gem 'sidekiq'

# Optional additions
gem 'sidekiq-scheduler'   # cron-like scheduling
gem 'sidekiq-unique-jobs'  # job uniqueness
gem 'sidekiq-cron'         # recurring jobs
bundle install

Rails Setup

# config/application.rb
config.active_job.queue_adapter = :sidekiq
# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.redis = { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') }
end

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

Job Definition

Basic Worker

# app/workers/hard_worker.rb
class HardWorker
  include Sidekiq::Worker

  sidekiq_options queue: 'default', retry: 5, backtrace: true

  def perform(name, count)
    # Do work
    puts "Processing #{name} with count #{count}"
  end
end

ActiveJob Worker

# app/jobs/process_order_job.rb
class ProcessOrderJob < ApplicationJob
  queue_as :high_priority
  retry_on StandardError, wait: :polynomially_longer, attempts: 5
  discard_on ActiveJob::DeserializationError

  def perform(order_id)
    order = Order.find(order_id)
    order.process!
  end
end

Worker Options

class MyWorker
  include Sidekiq::Worker

  sidekiq_options(
    queue: 'critical',       # queue name
    retry: 10,               # max retries (default 25)
    backtrace: true,         # log full backtrace
    dead: true,              # move to dead queue after retries
    lock: :until_executed,   # uniqueness (with sidekiq-unique-jobs)
    tags: ['billing'],       # tags for filtering in UI
  )

  sidekiq_retry_in do |count, exception|
    # Custom retry interval
    10 * (count + 1)  # 10, 20, 30 seconds...
  end

  sidekiq_retries_exhausted do |msg, exception|
    # Called when all retries fail
    Bugsnag.notify(exception)
  end

  def perform(user_id)
    # work
  end
end

Enqueueing Jobs

# Perform asynchronously
HardWorker.perform_async('Bob', 5)

# Perform in the future
HardWorker.perform_in(5.minutes, 'Bob', 5)
HardWorker.perform_at(Time.now + 1.hour, 'Bob', 5)

# Using ActiveJob
ProcessOrderJob.perform_later(order.id)
ProcessOrderJob.set(wait: 5.minutes).perform_later(order.id)
ProcessOrderJob.set(queue: :low).perform_later(order.id)

# Bulk enqueue
args = users.map { |u| [u.id] }
Sidekiq::Client.push_bulk('class' => HardWorker, 'args' => args)

Worker Commands

CommandDescription
bundle exec sidekiqStart with defaults
bundle exec sidekiq -q critical,3 -q default,1Start with weighted queues
bundle exec sidekiq -c 25Set concurrency to 25 threads
bundle exec sidekiq -C config/sidekiq.ymlUse config file
bundle exec sidekiq -e productionSet environment

Configuration

Config File (config/sidekiq.yml)

---
:concurrency: 10
:timeout: 25
:queues:
  - [critical, 3]
  - [high, 2]
  - [default, 1]
  - [low, 1]

:limits:
  critical: 5

production:
  :concurrency: 25

staging:
  :concurrency: 10

Scheduled / Recurring Jobs

# config/sidekiq_scheduler.yml (with sidekiq-scheduler)
cleanup_job:
  cron: '0 */6 * * *'    # every 6 hours
  class: CleanupWorker
  queue: maintenance

daily_report:
  cron: '0 8 * * *'      # daily at 8am
  class: DailyReportWorker
  args: ['summary']

heartbeat:
  every: '30s'
  class: HeartbeatWorker

Middleware

# Custom server middleware
class LoggingMiddleware
  def call(worker, job, queue)
    start = Time.now
    yield
    duration = Time.now - start
    Rails.logger.info "#{worker.class} completed in #{duration}s"
  end
end

Sidekiq.configure_server do |config|
  config.server_middleware do |chain|
    chain.add LoggingMiddleware
  end
end

Web UI

# config/routes.rb
require 'sidekiq/web'

Rails.application.routes.draw do
  # With authentication (production)
  authenticate :user, ->(u) { u.admin? } do
    mount Sidekiq::Web => '/sidekiq'
  end
end
# Standalone Rack app
# config.ru
require 'sidekiq/web'

Sidekiq::Web.use(Rack::Auth::Basic) do |user, password|
  [user, password] == ['admin', ENV['SIDEKIQ_PASSWORD']]
end

run Sidekiq::Web

Advanced Usage

Batches (Sidekiq Pro)

batch = Sidekiq::Batch.new
batch.description = "Import users batch"
batch.on(:success, BatchCallback, account_id: account.id)
batch.on(:complete, BatchCallback, account_id: account.id)

batch.jobs do
  users.each { |u| ImportWorker.perform_async(u.id) }
end

Job Filtering and Management

# Find and manage jobs in queues
queue = Sidekiq::Queue.new('default')
queue.size                          # number of jobs
queue.clear                         # delete all jobs
queue.each { |job| job.delete }     # iterate

# Scheduled jobs
ss = Sidekiq::ScheduledSet.new
ss.size
ss.each { |job| job.reschedule(Time.now) }

# Retry set
rs = Sidekiq::RetrySet.new
rs.size
rs.each { |job| job.retry }        # retry now
rs.clear                           # clear all retries

# Dead set
ds = Sidekiq::DeadSet.new
ds.each { |job| job.retry }

Rate Limiting

class ApiWorker
  include Sidekiq::Worker

  LIMITER = Sidekiq::Limiter.concurrent(
    'api-calls', 5, wait_timeout: 10
  )

  def perform(user_id)
    LIMITER.within_limit do
      ApiClient.fetch(user_id)
    end
  end
end

Monitoring

# Get real-time stats
stats = Sidekiq::Stats.new
stats.processed         # total processed
stats.failed            # total failed
stats.enqueued          # currently enqueued
stats.scheduled_size    # scheduled jobs
stats.retry_size        # jobs in retry
stats.dead_size         # dead jobs
stats.processes_size    # running processes
stats.workers_size      # active workers
# Health check endpoint (Sidekiq 7+)
curl http://localhost:7433/

Troubleshooting

IssueSolution
Jobs not processingCheck Redis connection; ensure Sidekiq process is running
Jobs stuck in retryCheck error in web UI; fix the bug and clear retries
Memory growingSet MALLOC_ARENA_MAX=2; check for memory leaks in workers
Redis connection issuesIncrease pool size; verify Redis URL; check connection limits
Jobs running twiceEnsure unique job processing; make jobs idempotent
Slow queue processingIncrease concurrency; add more Sidekiq processes; optimize job code
Dead jobs accumulatingReview sidekiq_retries_exhausted callback; fix recurring errors
Deployment issuesUse Sidekiq.configure_server to handle connection correctly; use USR1 signal for quiet