How to Cancel Scheduled Job with Delayed_Job in Rails

How to cancel scheduled job with delayed_job in Rails?

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?

Active Job - How to cancel a scheduled Action Mailer job?

I decided to approach the problem differently. Instead of scheduling a job and destroying it, I'm just simply scheduling a job.

When the user sets up a reminder for three days in the future, a job is created, just as before. If the user removes the email reminder, the job will still run in three days but won't do anything. Here's an example setup:

# controllers/users_controller.rb

def schedule_reminder
# Get the user that scheduled the reminder
user = User.find_by_id(params[:id])

# Create a reminder for the user
reminder = user.reminders.create(active: true)

# Schedule the reminder to be sent out
SendReminderJob.set(wait_until: 3.days.from_now).perform_later(reminder.id)
end

def unschedule_reminder
reminder = Reminder.find_by_id(params[:reminder_id])

reminder.destroy
end

When the user schedules a reminder, def schedule_reminder is executed. This method creates a reminder and schedules a job that will run in 3 days. It passes in the reminder's ID as an argument so the job can retrieve the reminder when it runs.

When the user deletes the reminder, def unschedule_reminder is executed. This method finds the reminder and deletes it.

Here's what my SendReminderJob job looks like:

# jobs/send_reminder_job.rb

class SendReminderJob < ActiveJob::Base
queue_as :default

def perform(*args)
# Get the reminder
# args.first is the reminder ID
reminder = Reminder.find_by_id(args.first)

# Check if the reminder exists
if !reminder.nil?
# Send the email to the user

end
end
end

When this job runs in three days, it checks to see if the reminder is still set. If it is, it sends out an email to the user. Otherwise, it does nothing. Regardless of whether or not it does anything, this job is deleted after three days!

delayed_job. Delete job from queue

Sounds like you want to de-queue any jobs if a radar object gets updated and re-queue.

Delayed::Job.enqueue should return a Delayed::Job record, so you can grab the ID off of that and save it back onto the Radar record (create a field for it on radar document) so you can find it again later easily.

You should change it to a before_save so you don't enter an infinite loop of saving.

before_save :post_on_facebook

def post_on_facebook
if self.user.settings.post_facebook && self.valid?

# delete existing delayed_job if present
Delayed::Job.find(self.delayed_job_id).destroy if self.delayed_job_id

# enqueue job
dj = Delayed::Job.enqueue(
::FacebookJob.new(self.user,self.body,url,self.title),0,self.active_from
)

# save id of delayed job on radar record
self.delayed_job_id = dj.id

end
end

Is it possible to terminate an already running delayed job using Ruby Threading?

It seems that my boss hit the spot so here's what we did(please tell us if there's some possibility this is bad practice so I can bring it up):

  1. First, we have a Job model that has def execute! (which runs what it's supposed to do).
  2. Next, we have delayed_job worker in the background, listening for new jobs. Now when you create a job, you can schedule it to run immediately or run every certain day (we use rufus for this one)
  3. When a job is created, it checks if its supposed to run immediately. If it is, it adds itself to the delayed job queue. The execute function creates a Thread, so each job has its own thread.
  4. User in the ui can see if a job is running(if there's a started_at and no finished_at). If it IS running, there's a button to cancel it. Canceling it just sets the job's canceled_at to Time.now.
  5. While the job is running it also checks itself if it has a canceled_at or if Time.now is > finished_at. If so, kill the thread.

Voila! We've tested it for one job and it seems to work. Now the only problem is scaling...

If you see any problems with this please do so in the comments or give more suggestions if ever :) I hope this helps some one too!

Delayed Job: How to retrieve and update a scheduled job?

You can simply work on the Delayed::Job model (say activerecord if you use delayed_job_active_record)

The question is what job you want to retrieve, and how you take care of that.
No matter how you manage your jobs for later retrieval, you should use something like:

# submit the job and remember id
job_id_remember_for_later = Delayed::Job.enqueue(job).id
#...
# later
job = Delayed::Job.find_by_id(job_id_remember_for_later)
job.update_attributes(:run_at => new_time, :attempts => 0)
job.save

This code is surely unsafe, you need to check lock, etc.
Also note that you need to config delayed_job to keep failed jobs (deleted by default after max_attempts failures).

Delayed::Worker.destroy_failed_jobs = false

How to pause and resume delayed_job tasks in rails

There's, unfortunately, no built-in way to pause and resume jobs with delayed_job. See the following GitHub issue: https://github.com/collectiveidea/delayed_job/issues/58

This is not to say you can't accomplish this with additional work. You could have you job periodically check your database to see if it should wait before continuing. Defining how to accomplish "waiting" is another story. More than likely, you best bet is to design a way for the "pause" action to stop the current job and save its state. "Resuming" would then fire up another job that continues where it left off.



Related Topics



Leave a reply



Submit