How to cancel scheduled job with delayed_job in Rails?
Solution 1
disclaimer: I am not an expert user of delayed_job...
"Is there any call to remove particular job, or jobs related to specific model, instance, etc?"
Delayed::Job is just an ActiveRecord object so you can find and destroy any of those records. Depending on your use case this could be handled different ways. If someone is going to manually destroy them this could be handled through an admin interface in your web app.
# list all jobs
Delayed::Job.all
# find a job by id
job = Delayed::Job.find(params[:id])
# delete it
job.delete
if you need some out of process task deleting jobs by 'job type' you could loop through each one and delete it if it matches your job; try this in script/console
class MyJob < Struct.new(:some_value);
def perform
# ...
end
end
my_job = MyJob.new('xyz')
job = Delayed::Job.enqueue(my_job, 0, 1.hour.from_now)
job.name
# => "MyJob"
job.handler
# => "--- !ruby/struct:MyJob \nsome_value: xyz\n"
so given the above if you wanted to delete all jobs of type MyJob
Delayed::Job.all.each do |job|
if job.name == "MyJob" then
job.delete
end
end
this may or may not help for your situation? in many cases you might want to delete a MyJob but only where the :some_value attribute was 'abc' and not 'xyz'. In this case you might need to implement a 'display_name' on your MyJob object. job.name will use this if it exists
class MyJob < Struct.new(:user_id);
def perform
# ...
end
def display_name
return "MyJob-User-#{user_id}"
end
end
# store reference to a User
my_job = MyJob.new(User.first.id) # users.id is 1
job = Delayed::Job.enqueue(my_job, 0, 1.hour.from_now)
job.name
# => "MyJob-User-1"
job.handler
# => "--- !ruby/struct:MyJob \nuser_id: 1\n"
this way you could be more selective about which records to delete?
hopefully this gives you enough information on possible ways to handle it?
Solution 2
delayed_job 3 introduced a queue
attribute. This can be hijacked to schedule a cancelable job.
class MyJob < Struct.new(:user_id)
def self.queue_name
"something-unique"
end
def perform
# ...
end
end
#scheduler
my_job = MyJob.new(User.first.id)
#'cancel' pending jobs first
Delayed::Job.where(queue: my_job.class.queue_name).destroy_all
#queue it up
Delayed::Job.enqueue(my_job,
queue: my_job.class.queue_name,
run_at: 1.hour.from_now
)
Comments
-
mdrozdziel almost 4 years
I am scheduling a job to run in say, 10 minutes. How to properly cancel this particular job without using any kind of dirty extra fields in model and so on. Is there any call to remove particular job, or jobs related to specific model, instance, etc?
-
Brandon Bloom over 13 yearsYou should probably use "destroy" instead of "delete".
-
Dex almost 9 yearsI would really not recommend doing things this way. The
queue
is meant to allow the app to scale. You've already gone through with a custom Struct, just pick a different attribute name house9 did. -
Vox over 6 yearsIn order to loop over all the delayed jobs you need to do
Delayed::Job.all.each do |job|
. (Need the .each). -
Pere Joan Martorell almost 4 yearsas far as I know this won't stop/cancel a job that is already being performed, right?
-
house9 almost 4 years@PereJoanMartorell - you are correct, this will not cancel a job already running, the only way I know how to do that is to stop the DJ process and then delete the job record.