Categories
Ruby Sidekiq

Sidekiq: Invalidate jobs without batches

So you have a bunch of jobs lined up in Sidekiq.

But for some reason (user action, etc) you don’t need those jobs to execute anymore. So what do you do?

You could go ahead and delete them the way Sidekiq docs outline:

queue = Sidekiq::Queue.new("queue")
queue.each do |job|
  job.delete if job.jid == 'abcdef1234567890'
end

This approach is extremely counterproductive. What if you have a huge queue with thousands of jobs lined up? Do you need to iterate through the queue for each job you need to delete? Unfortunately, Sidekiq does not provide an adequate approach to tackle this issue. Fortunately though, there is another way! You could create a key on redis that blocks the execution of a corresponding job:

def invalidate_all(ids, time)
  Sidekiq.redis do |r|
    ids.each do |id|
      r.setex("invalidated-jid-#{id}", 60, 1)
    end
  end
end

def is_job_valid?(id)
 !Sidekiq.redis { |r| r.exists("invalidated-jid-#{id}") }
end

def perform
  ...
  job_id = 'abcdef1234567890'
  return unless is_job_valid?(job_id)
  ...
end
  • invalidate_all function creates “blocking” keys in Sidekiq that we’d check when the job tries to execute. The key expires after 60 seconds. You can modify the function to have each key exist for a different amount of time.
  • is_job_valid? checks the validity of a job, by checking if a corresponding key that was created in  invalidate_all still exists.
  • perform function, which you would define in your queued object worker, checks to see if the “blocking” key exists. If it does, then it returns and doesn’t execute the job. If the key doesn’t exist or has been expired (they both mean the same thing), then it continues with the execution.

Ands thats that! Its worth a mention that this approach was inspired by what goes on under the hood for batch cancelation.