how to delete a job in sidekiq
Asked Answered
C

8

59

I am using sidekiq in my rails app. Users of my app create reports that start a sidekiq job. However, sometimes users want to be able to cancel "processing" reports. Deleting the report is easy but I also need to be able to delete the sidekiq job as well.

So far I have been able to get a list of workers like so:

workers = Sidekiq::Workers.new

and each worker has args that include a report_id so I can identify which job belongs to which report. However, I'm not sure how to actually delete the job. It should be noted that I want to delete the job whether it is currently busy, or set in retry.

Creon answered 13/1, 2014 at 21:0 Comment(0)
P
110

According to this Sidekiq documentation page to delete a job with a single id you need to iterate the queue and call .delete on it.

queue = Sidekiq::Queue.new("mailer")
queue.each do |job|
  job.klass # => 'MyWorker'
  job.args # => [1, 2, 3]
  job.delete if job.jid == 'abcdef1234567890'
end

There is also a plugin called sidekiq-status that provides you the ability to cancel a single job

scheduled_job_id = MyJob.perform_in 3600
Sidekiq::Status.cancel scheduled_job_id #=> true
Patriliny answered 13/1, 2014 at 21:33 Comment(6)
For your first piece of code, isn't that deleting jobs out of the queue? what if it is already busy or in retries?Creon
As far as I can see, in both cases there is no way to kill a job that is already running.Patriliny
Well...that seems pretty unintuitive, right? I just have to accept the job will run until completion even if I need it stopped?Creon
That's the way it is right now. Killing a running job will require to either store who is the worker and send a signal to the worker, but will also need a supervisor. It's not trivial.Patriliny
It seems like the code above may be paginated so if you have a particularly large set of jobs (eg > 5000), you might need to run multiple times.Hawthorn
@Hawthorn Try running the code after pausing the queue. In my experience that works without breaking the execution.Sweet
P
32

The simplest way I found to do this is:

job = Sidekiq::ScheduledSet.new.find_job([job_id])

where [job_id] is the JID that pertains to the report. Followed by:

job.delete

I found no need to iterate through the entire queue as described by other answers here.

Photozincography answered 11/8, 2015 at 0:11 Comment(3)
find_job uses the same linear search. This is a comment from documentation: "this is very inefficient if your queue is big!"Corm
@Corm what do you suggest instead?Cardialgia
Find a job by JID (WARNING: this is very inefficient if your queue is big!)Sickroom
S
20

I had the same problem, but the difference is that I needed to cancel a scheduled job, and my solution is:

Sidekiq::ScheduledSet.new.each do |_job|
  next unless [online_jid, offline_jid].include? _job.jid
  status = _job.delete
end
Sufferance answered 11/4, 2014 at 9:25 Comment(1)
What is create_log for?Heredity
V
9

You can delete sidekiq job filtering by worker class and args:

class UserReportsWorker
  include Sidekiq::Worker
  def perform(report_id)
    # ...
  end
end


jobs = Sidekiq::ScheduledSet.new.select do |retri| 
  retri.klass == "UserReportsWorker" && retri.args == [42]
end
jobs.each(&:delete)
Varicotomy answered 17/8, 2016 at 20:4 Comment(0)
H
7

If you want to cancel a scheduled job, I'm not sure about @KimiGao's answer, but this is what I adapted from Sidekiq's current API documentation:

jid = MyCustomWorker.perform_async

r = Sidekiq::ScheduledSet.new
jobs = r.select{|job| job.jid == jid }
jobs.each(&:delete)

Hope it helps.

Heredity answered 14/1, 2015 at 23:1 Comment(0)
V
3

I had the same problem. I solved it by registering the job id when I initialize it and by creating another function cancel! to delete it.

Here is the code:

after_enqueue do |job|
  sidekiq_job = nil

  queue = Sidekiq::Queue.new
  sidekiq_job = queue.detect do |j|
    j.item['args'][0]['job_id'] == job.job_id
  end

  if sidekiq_job.nil?
    scheduled = Sidekiq::ScheduledSet.new
    sidekiq_job = scheduled.detect do |j|
      j.item['args'][0]['job_id'] == job.job_id
    end
  end

  if sidekiq_job.present?
    booking = job.arguments.first
    booking.close_comments_jid = sidekiq_job.jid
    booking.save
  end
end


def perform(booking)
   # do something
end

def self.cancel!(booking)
  queue = Sidekiq::Queue.new
  sidekiq_job = queue.find_job(booking.close_comments_jid)

  if sidekiq_job.nil?
    scheduled = Sidekiq::ScheduledSet.new
    sidekiq_job = scheduled.find_job(booking.close_comments_jid)
  end

  if sidekiq_job.nil?
    # Report bug in my Bug Tracking tool
  else
    sidekiq_job.delete

  end
end
Variation answered 5/2, 2016 at 11:37 Comment(0)
R
3

There is simple way of deleting a job if you know the job_id:

job = Sidekiq::ScheduledSet.new.find_job(job_id)
begin
  job.delete
rescue
  Rails.logger.error "Job: (job_id: #{job_id}) not found while deleting jobs."
end
Rozele answered 17/9, 2016 at 9:16 Comment(0)
J
2

Or you can use sidekiq page on rails server.

For example, http://localhost:3000/sidekiq, you can stop/remove the sidekiq jobs.

Before that, you have to updates the routes.rb.

require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
Jurist answered 29/12, 2018 at 22:42 Comment(1)
It's important to note this is only for jobs which are still in the queue or scheduled. For jobs that are busy and still-running, this does not change anything.Derk

© 2022 - 2024 — McMap. All rights reserved.