Skip to content

Instantly share code, notes, and snippets.

@Aethelflaed
Last active August 29, 2015 14:19
Show Gist options
  • Save Aethelflaed/d2e1200c3f480afb6726 to your computer and use it in GitHub Desktop.
Save Aethelflaed/d2e1200c3f480afb6726 to your computer and use it in GitHub Desktop.
Rails ActiveJob CronJob

I had to create some recurring jobs, so I decided to implement a simple CronJob module to work this that.

The CronJob module creates an after_perform callback to reschedule the job at the next_occurence, with the same arguments.

I used https://github.com/siebertm/parse-cron to parse the cron expression.

module CronJob
extend ActiveSupport::Concern
included do
# class_attribute set one different value for each subclasses
class_attribute :cron_exp
after_perform do |job|
# Do you want to reschedule and is there a next occurence ?
if job.reschedule && job.next_occurence
# Then perform again at next occurence
job.class.perform_at_next_occurence(job.arguments, job.next_occurence)
end
end
end
def next_occurence(time = nil)
self.class.next_occurence(time)
end
def reschedule(value = nil)
@reschedule = value if !value.nil?
@reschedule = true if @reschedule.nil?
@reschedule
end
class_methods do
# Helper to get/set the cron_exp class_attribute
def cron(value = nil)
self.cron_exp = value if value
self.cron_exp
end
# Calculate the next occurence from the cron_exp and the given (or current) time.
def next_occurence(time = nil)
return if !self.cron
time ||= Time.now
CronParser.new(self.cron).next(time)
end
def perform_at_next_occurence(arguments, occurence = nil)
occurence ||= self.next_occurence
set(wait_until: occurence).perform_later(*arguments)
end
end
end
# Example of how I use it
class BackupJob < ActiveJob::Base
# Include the module
include CronJob
queue_as :backup
# Specify the cron expression, it's the same as `self.cron_exp = '0 3 * * *'`
cron '0 3 * * *'
# The perform method itself could have no arguments, this one is just here to enabled backup on demand
# without rescheduling a new backup
def perform(requested = false)
reschedule !requested # reschedule only if not requested
# perform backup
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment