How to kill Sidekiq jobs in Ruby on Rails
By Elom Gomez |
We’ve have all run into situations where we’d like to disable or cancel an errant Sidekiq job in production. The current solutions involve dumping the deploy queue for the specific job or deploying a hot fix to production to disable the job. Initially, these solutions tend to solve your problem, but as your app grows and your job queue gets complicated, you’ll want a solution that is more robust and almost immediate.
In this post, we will learn how we built a Sidekiq Client Middleware to kill Sidekiq jobs in production without relying on deploys.
Sidekiq Client Middleware
We currently make use of the amazing flipper
gem at PlanetScale to feature flag new features being built. One of the major pros of Flipper is that it allows us to enable/disable different code paths in production without deploys. Based on this, we decided to use its feature flagging capabilities to help us disable our jobs in production. We created a middleware, lib/sidekiq_middleware/sidekiq_jobs_flipper.rb
, which you can find below:
module SidekiqMiddleware class SidekiqJobsFlipper def call(worker_class, job, queue, redis_pool) # return false/nil to stop the job from going to redis klass = worker_class.to_s if Flipper.enabled?("disable_#{klass.underscore.to_sym}") return false end yield end end end
The Sidekiq client middleware runs when pushing a job to Redis. The following snippet from the middleware allows us to short circuit any jobs that have been feature flagged to be disabled:
if Flipper.enabled?("disable_#{klass.underscore.to_sym}") return false end
Example usage
If you want to disable jobs in production in your own application, you can use this middleware.
Create a new middleware file and paste in the middleware code from the previous section.
Add the middleware to your Sidekiq configurations in
config/initializers/sidekiq.rb
:
Sidekiq.configure_server do |config| config.client_middleware do |chain| chain.add(SidekiqMiddleware::SidekiqJobsFlipper) end end
- To disable a job in production, you would
.underscore
the job class name and prefix it withdisable_
. Let’s take theInvoiceJob
below as an example:
class InvoiceJob include Sidekiq::Worker def perform(...) ... end end
In this case, the class name InvoiceJob
becomes disable_invoice_job
.
- To disable
InvoiceJob
, run the following command in the console:
Flipper.enable("disable_invoice_job")