Skip to content

Instantly share code, notes, and snippets.

@eparreno
Last active September 5, 2023 17:38
Show Gist options
  • Star 33 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save eparreno/9f82d6012e6585a9346b to your computer and use it in GitHub Desktop.
Save eparreno/9f82d6012e6585a9346b to your computer and use it in GitHub Desktop.
How to delete Sidekiq jobs in a Rails app using ActiveJobs

How to delete Sidekiq jobs in a Rails app using ActiveJobs

Sidekiq jobs can be enqueued or scheduled. Enqueued means that they are gonna be picked up as soon as possible, scheduled jobs will be enqueued at some specific time.

job_id and jid

When using ActiveJobs, Rails will return a job_id after sending the job to ActiveJobs

job = UserMailer.send_invite(params).deliver_later
job.job_id => "9fb7b1f3-0159-49dd-b886-dfb8df991cd6"

Keep in mind that this is not the id Sidekiq uses to reference jobs internally. To get the Sidekiq jid

# enqueued jobs
job = UserMailer.send_invite(params).deliver_later
Sidekiq::Queue.new("mailers").find { |job_id| job.job_id }.item["jid"]

# scheduled jobs
job = UserMailer.send_invite(params).deliver_later(wait: 1.hour)
Sidekiq::ScheduledSet.new.find { |job_id| job.job_id }.item["jid"]

Enqueued jobs

Here's a typical example in a Rails app

job = UserMailer.send_invite(params).deliver_later

That jobs will go straight to the queue and will get processed as soon as possible. Keep in mind that Sidekiq is fast as hell so if there are enough resources that job will be executed with virtually no delay, so it's almost impossible to delete a job from the queue unless Sidekiq is busy processing other jobs, that will give you some time to delete the job.

queue = Sidekiq::Queue.new("mailer")
queue.each do |job|
  # using jid
  job.delete if job.jid == 'sidekiq_job_id'
  # using job_id
  job.delete if job.job_id == 'rails_job_id'
end

Scheduled jobs

In that case you'll have a bit more time to delete the job ;)

job = UserMailer.send_invite(params).deliver_later(wait: 1.hour)
ss = Sidekiq::ScheduledSet.new
ss.select { |job_id| job.job_id }.each(&:delete)

or using the jid

jid = Sidekiq::ScheduledSet.new.find { |job_id| job.job_id }.item["jid"]
Sidekiq::ScheduledSet.new.find_job(jid).delete

or matching jobs by class instead of by ID

ss = Sidekiq::ScheduledSet.new
jobs = ss.select {|job| job.klass == 'SomeWorker' }
jobs.each(&:delete)
@vrinek
Copy link

vrinek commented Oct 29, 2015

Sidekiq::Queue.new("mailers").find { |job_id| job.job_id }.item["jid"] looks like is should be Sidekiq::Queue.new("mailers").find { |job_id| job_id == job.job_id }.item["jid"]

@vrinek
Copy link

vrinek commented Oct 29, 2015

I'm a little worried that adding a delay to some jobs will be unacceptable (product-wise).

In particular, imagine the "guest creates new trip" flow on TripGun:

  • I create a trip, add legs, input my email and click "Go!"
  • The mobile app notifies me that a confirmation email will arrive shortly
  • Without the delay -- within seconds (hopefully the time it took me to read the text on the previous step) I see a push notification that I just received an email, tap to view and tap to confirm
  • With the delay -- I don't see any notification popping up so I either head to my mail client and refresh or just lock my phone and put it back to my pocket

In particular, I would hate our first time users to put their phone back in their pocket because it might take them some time (hours, days) to check their email again. Since this is a product thing I would expect others have more to-the-point feedback to give.

@eparreno
Copy link
Author

I totally agree. I'm not saying we should delay all the jobs to have time to delete them, just pointing out all the options available.

@olegsobchuk
Copy link

olegsobchuk commented Jul 14, 2016

job = UserMailer.send_invite(params).deliver_later
job.job_id => "9fb7b1f3-0159-49dd-b886-dfb8df991cd6" ActiveJob id
job.provider_job_id => "5f4cbb0d87a46ec845b6ea92" Sidekiq id

@noel9999
Copy link

I think Sidekiq::Queue.new("mailers").find { |entry| entry.args.first.fetch('job_id') == job.job_id } would be the right way to find a corresponding job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment