Sidekiq: bulk manipulation of jobs and processes
Sidekiq series — part 3 of 4
- Infra: starting, stopping, killing
- Diagnosis via console
- You are here — Bulk manipulation
- UI hacks in the dashboard
After diagnosing (part 2), the invasive part usually follows: getting a problematic worker out of the way, reorganizing the queue, deleting jobs that no longer make sense. This post is the toolbox for that.
The
; nilat the end of blocks is just to preventrails consolefrom printing thousands of lines when the collection is large.
Selecting retry jobs by class name
1
2
3
job_class_name = 'SidekiqTest::SidekiqTestWorker'
jobs = Sidekiq::RetrySet.new.select { |job| job.klass == job_class_name }; nil
jobs.size
Selecting dead jobs by class name
1
2
3
job_class_name = 'SidekiqTest::SidekiqTestWorker'
jobs = Sidekiq::DeadSet.new.select { |job| job.klass == job_class_name }; nil
jobs.size
Selecting queued jobs in a queue by class name
1
2
3
4
queue_name = 'default'
job_class_name = 'SidekiqTest::SidekiqTestWorker'
jobs = Sidekiq::Queue.new(queue_name).select { |job| job.klass == job_class_name }; nil
jobs.count
Re-queuing selected jobs for retry
1
jobs.each(&:retry)
Applies to any collection of jobs from RetrySet or DeadSet. Moves everything back to the original queue.
Deleting selected jobs
1
jobs.each(&:delete)
Same pattern, with the inverse operation. Use once you’re sure you can discard them — there’s no going back.
Moving 1000 jobs of a class to another queue
1
2
3
4
5
6
7
8
9
10
queue_name = 'default'
new_queue_name = 'funnels_test_worker'
queue = Sidekiq::Queue.new(queue_name)
queue.first(1000).each do |job|
if job.klass == "SidekiqTest::SidekiqTestWorker"
SidekiqTest::SidekiqTestWorker.set(queue: new_queue_name).perform_async(*job.args)
job.delete
end
end; nil
This is the snippet that saves the day most often. When a worker is bringing down a shared queue, instead of pausing everything, I:
- Create a dedicated queue (
funnels_test_worker) - Move the problematic jobs to it
- Spin up a separate Sidekiq process consuming that queue with reduced concurrency (e.g. 1 thread)
The rest of the operation doesn’t feel it — and I can debug the worker calmly without pressuring the main queue.
Quieting processes for deploy
1
2
ps = Sidekiq::ProcessSet.new
ps.each(&:quiet!)
quiet! makes each process stop picking up new jobs, but finish the ones currently running. The polite way to drain before bringing down — good for deploys that don’t use an orchestrator.
Stopping processes via API
1
2
ps = Sidekiq::ProcessSet.new
ps.each(&:stop!)
Equivalent to sidekiqctl stop from part 1, but via console instead of shell.
Clear all of Sidekiq’s Redis — DELETES EVERYTHING
1
Sidekiq.redis { |conn| conn.flushdb }
Nuclear bomb: deletes everything Sidekiq has in Redis (queues, retries, dead set, stats). Only use this when you know you can reprocess safely or you’re on a dev machine. In production, this is an incident — only do it with a clear recovery plan.
Next in the series
UI hacks for the Sidekiq dashboard — when the retries screen has 100,000 items and the native UI can’t cope.