lib/rocket_job/plugins/restart.rb in rocketjob-3.1.0 vs lib/rocket_job/plugins/restart.rb in rocketjob-3.2.0
- old
+ new
@@ -1,53 +1,97 @@
require 'active_support/concern'
module RocketJob
module Plugins
# Automatically starts a new instance of this job anytime it fails, aborts, or completes.
- # Failed jobs are aborted so that they cannot be restarted.
- # On destroy this job is destroyed without starting a new copy. Abort the job first to get
- # it to start a new instance before destroying.
- # Include RocketJob::Plugins::Singleton to prevent multiple copies of a job from running at
- # the same time.
#
- # Note:
- # - The job will not be restarted if:
- # - A validation fails after cloning this job.
+ # Notes:
+ # * Restartable jobs automatically abort if they fail. This prevents the failed job from being retried.
+ # - To disable this behavior, add the following empty method:
+ # def rocket_job_restart_abort
+ # end
+ # * On destroy this job is destroyed without starting a new instance.
+ # * On Abort a new instance is created.
+ # * Include `RocketJob::Plugins::Singleton` to prevent multiple copies of a job from running at
+ # the same time.
+ # * The job will not be restarted if:
+ # - A validation fails after creating the new instance of this job.
# - The job has expired.
+ # * Only the fields that have `copy_on_restart: true` will be passed onto the new instance of this job.
+ #
+ # Example:
+ #
+ # class RestartableJob < RocketJob::Job
+ # include RocketJob::Plugins::Restart
+ #
+ # # Retain the completed job under the completed tab in Rocket Job Mission Control.
+ # self.destroy_on_complete = false
+ #
+ # # Will be copied to the new job on restart.
+ # field :limit, type: Integer, copy_on_restart: true
+ #
+ # # Will _not_ be copied to the new job on restart.
+ # field :list, type: Array, default: [1,2,3]
+ #
+ # # Set run_at every time a new instance of the job is created.
+ # after_initialize set_run_at, if: :new_record?
+ #
+ # def perform
+ # puts "The limit is #{limit}"
+ # puts "The list is #{list}"
+ # 'DONE'
+ # end
+ #
+ # private
+ #
+ # # Run this job in 30 minutes.
+ # def set_run_at
+ # self.run_at = 30.minutes.from_now
+ # end
+ # end
+ #
+ # job = RestartableJob.create!(limit: 10, list: [4,5,6])
+ # job.reload.state
+ # # => :queued
+ #
+ # job.limit
+ # # => 10
+ #
+ # job.list
+ # # => [4,5,6]
+ #
+ # # Wait 30 minutes ...
+ #
+ # job.reload.state
+ # # => :completed
+ #
+ # # A new instance was automatically created.
+ # job2 = RestartableJob.last
+ # job2.state
+ # # => :queued
+ #
+ # job2.limit
+ # # => 10
+ #
+ # job2.list
+ # # => [1,2,3]
module Restart
extend ActiveSupport::Concern
included do
- # Attributes to exclude when copying across the attributes to the new instance
- class_attribute :rocket_job_restart_excludes
- self.rocket_job_restart_excludes = %w(_id state created_at started_at completed_at failure_count worker_name percent_complete exception result run_at record_count sub_state)
-
after_abort :rocket_job_restart_new_instance
after_complete :rocket_job_restart_new_instance
after_fail :rocket_job_restart_abort
end
- module ClassMethods
- def field(name, options)
- if options.delete(:copy_on_restart) == false
- self.rocket_job_restart_excludes += [name.to_sym] unless rocket_job_restart_excludes.include?(name.to_sym)
- end
- super(name, options)
- end
- end
-
private
# Run again in the future, even if this run fails with an exception
def rocket_job_restart_new_instance
+ logger.info('Job has expired. Not creating a new instance.')
return if expired?
- attrs = attributes.dup
- rocket_job_restart_excludes.each { |attr| attrs.delete(attr) }
-
- # Copy across run_at for future dated jobs
- attrs['run_at'] = run_at if run_at && (run_at > Time.now)
-
+ attrs = rocket_job_restart_attributes.reduce({}) { |attrs, attr| attrs[attr] = send(attr); attrs }
rocket_job_restart_create(attrs)
end
def rocket_job_restart_abort
new_record? ? abort : abort!
@@ -58,21 +102,20 @@
def rocket_job_restart_create(attrs, retry_limit = 3, sleep_interval = 0.1)
count = 0
while count < retry_limit
job = self.class.create(attrs)
if job.persisted?
- logger.info("Started a new job instance: #{job.id}")
+ logger.info("Created a new job instance: #{job.id}")
return true
else
logger.info('Job already active, retrying after a short sleep')
sleep(sleep_interval)
end
count += 1
end
logger.warn('New job instance not started since one is already active')
false
end
-
end
end
end