lib/rocket_job/plugins/cron.rb in rocketjob-3.3.4 vs lib/rocket_job/plugins/cron.rb in rocketjob-3.4.0

- old
+ new

@@ -26,18 +26,25 @@ # A job is only queued to run at the specified `cron_schedule`, it will only run if there are workers # available to run. For example if workers are busy working on higher priority jobs, then the job # will only run once those jobs have completed, or their priority lowered. Additionally, while the # job is queued no additional instances will be enqueued, even if the next cron interval has been reached. # - # Note: + # Notes: # - The job will not be restarted if: # - A validation fails after cloning this job. # - The job has expired. # - Any time the `cron_schedule` is changed, the `run_at` is automatically set before saving the changes. - # - However, if the `run_at` is explicitly set then it will not be overriden. + # - However, if the `run_at` is explicitly set then it will not be overridden. + # - `cron_schedule` is not a required field so that the same job class + # - can be scheduled to run at regular intervals, + # - and run on an ad-hoc basis with custom values. + # - On job failure + # - a new future instance is created immediately. + # - the current instance is marked as failed and its cron schedule is set to nil. + # - Prevents the failed instance from creating a new future instance when it completes. # - # Example: + # Example, schedule the job to run at regular intervals: # # class MyCronJob < RocketJob::Job # include RocketJob::Plugins::Cron # # # Set the default cron_schedule @@ -46,24 +53,46 @@ # def perform # puts "DONE" # end # end # - # # Queue the job for processing using the default cron_schedule specified above + # # Queue the job for processing using the default cron_schedule specified above. # MyCronJob.create! # - # # Set the cron schedule: - # MyCronJob.create!(cron_schedule: '* 1 * * * America/New_York') # + # Example, a job that can run at regular intervals, and can be run for ad-hoc reporting etc.: # - # Note: + # class ReportJob < RocketJob::Job + # # Do not set a default cron_schedule so that the job can also be used for ad-hoc work. + # include RocketJob::Plugins::Cron # - # To prevent multiple instances of the job from running at the same time, - # add: "include RocketJob::Plugins::Singleton" + # field :start_date, type: Date + # field :end_date, type: Date # - # Example: Only allow one instance of the cron job to run at a time: + # def perform + # # Uses `scheduled_at` to take into account any possible delays. + # self.start_at ||= scheduled_at.beginning_of_week.to_date + # self.end_at ||= scheduled_at.end_of_week.to_date # + # puts "Running report, starting at #{start_date}, ending at #{end_date}" + # end + # end + # + # # Queue the job for processing using a cron_schedule. + # # On completion the job will create a new instance to run at a future date. + # ReportJob.create!(cron_schedule: '* 1 * * * America/New_York') + # + # # Queue the job for processing outside of the above cron schedule. + # # On completion the job will _not_ create a new instance to run at a future date. + # job = ReportJob.create!(start_date: 30.days.ago, end_date: 10.days.ago) + # + # + # To prevent multiple instances of the job from running at the same time, add the singleton plug-in: + # include RocketJob::Plugins::Singleton + # + # Example: Only allow one instance of this job to be active at the same time (running, queued, scheduled, or failed): + # # class MyCronJob < RocketJob::Job # # Add `cron_schedule` # include RocketJob::Plugins::Cron # # Prevents mutiple instances from being queued or run at the same time # include RocketJob::Plugins::Singleton @@ -104,20 +133,51 @@ field :cron_schedule, type: String, class_attribute: true, user_editable: true, copy_on_restart: true before_save :rocket_job_set_run_at - validates_presence_of :cron_schedule validates_each :cron_schedule do |record, attr, value| begin - RocketJob::Plugins::Rufus::CronLine.new(value) + RocketJob::Plugins::Rufus::CronLine.new(value) if value rescue ArgumentError => exc record.errors.add(attr, exc.message) end end + + private + + # Prevent auto restart if this job does not have a cron schedule. + # Overrides: RocketJob::Plugins::Restart#rocket_job_restart_new_instance + def rocket_job_restart_new_instance + return unless cron_schedule + super + end + + # On failure: + # - create a new instance scheduled to run in the future. + # - clear out the `cron_schedule` so this instance will not schedule another instance to run on completion. + # Overrides: RocketJob::Plugins::Restart#rocket_job_restart_abort + def rocket_job_restart_abort + return unless cron_schedule + rocket_job_restart_new_instance + self.cron_schedule = nil + end end + # Returns [Time] at which this job was intended to run at. + # + # Takes into account any delays that could occur. + # Recommended to use this Time instead of Time.now in the `#perform` since the job could run outside its + # intended window. Especially if a failed job is only retried quite sometime later. + # + # Notes: + # * When `cron_schedule` is set, this would be the `run_at` time, otherwise it is the `created_at` time + # since that would be the intended time for which this job is running. + def scheduled_at + run_at || created_at + end + # Returns [Time] the next time this job will be scheduled to run at. # # Parameters # time: [Time] # The next time as of this time. @@ -127,9 +187,10 @@ end private def rocket_job_set_run_at + return unless cron_schedule self.run_at = rocket_job_cron_next_time if cron_schedule_changed? && !run_at_changed? end end end