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

2

5

I am using Delayed Job as my queuing backend for Active Job. I have not set up any custom jobs and plan on using Action Mailer to send out scheduled emails asynchronously. How can I prevent a scheduled email from being sent out?

For example, suppose the user can set up email reminders on my application. If the user sets up a reminder for three days in the future, a job will be created. If the user removes that email reminder, the job should be deleted.

Any help would be greatly appreciated!

Corpulent answered 26/1, 2016 at 21:38 Comment(0)
C
8

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!

Corpulent answered 5/2, 2016 at 21:17 Comment(0)
S
1

I created app/models/delayed_backend_mongoid_job.rb.

class DelayedBackendMongoidJob
  include Mongoid::Document    
  field :priority,      type: Integer
  field :attempts,      type: Integer
  field :queue,         type: String
  field :handler,       type: String
  field :run_at,        type: DateTime
  field :created_at,    type: DateTime
  field :updated_at,    type: DateTime
end

If you are using ActiveRecord you need to adjust the model file. Then I installed rails_admin and I can view/edit any of the records in that table.

If you have a job scheduled to run in 2 days all you have to do is delete the record and DJ will never pick it up.

Squier answered 27/1, 2016 at 0:22 Comment(4)
Thanks for your answer! How would I find the correct record to delete if my Delayed Job table is filled with similar jobs?Corpulent
You could use named queues so you can then filter them in rails_admin. Or you could add rails_admin field with formatted_value of :handler. Or add method to your model to grab the parameters from handler and filter by those in RASquier
I am not using rails_admin and would like to cancel the job automatically once the user removes the email reminder. Do you think named queues would still work? I need to retrieve the exact email reminder to delete it, and it is not practical for me to go through an interface and manually delete them.Corpulent
:handler should have some kind of unique ID for your email as the job needs it. Find record and delete it. #3638750Squier

© 2022 - 2024 — McMap. All rights reserved.