Search code examples
ruby-on-railscronbackground-processrake-task

Best way to trigger an hour before event starts


I have many Appointment models that start at various times of the day, either at :00, :15, :30, :45. I'd like to trigger code to send a reminder 1 hour before the event starts. What would be the best way to use a background worker to trigger this? I'm using the clockwork gem as well so I can schedule Sidekiq workers.


Solution

  • The clockwork gem is for fixed schedule jobs (a replacement for cron). You'll want to use ActionMailer.delay_until that comes with sidekiq:

    class Appointment
      after_create :queue_reminder
    
      def queue_reminder
        MyMailer.delay_until(event_time - 1.hour).appointment_reminder(id)
      end
    end
    

    See sidekiq docs here: https://github.com/mperham/sidekiq/wiki/Delayed-Extensions

    As shock_one mentioned, if you update an appointment with a new date, you'll have to requeue a reminder and cancel the old one. You'll also want to cancel a job if an Appointment is destroyed.

    For that, I'd advise you use sidekiq-status, and a reminder_job_id column. Your Appointment model would then look something like:

    class Appointment
      before_save :queue_reminder, if: :event_time_changed?
      after_destroy :cancel_reminder, if: :reminder_job_id?
    
      def queue_reminder
        cancel_reminder if reminder_job_id
        self.reminder_job_id = MyMailer.delay_until(event_time - 1.hour)
                                       .appointment_reminder(id)
      end
    
      def cancel_reminder
        Sidekiq::Status.cancel reminder_job_id
      end
    end