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 ininvalidate_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 expired (they both mean the same thing), then it continues with the execution.
And that’s that! It’s worth a mention that this approach was inspired by what goes on under the hood for batch cancelation.