module OscMacheteRails::Statusable

Methods that deal with pbs batch job status management within a Rails ActiveRecord model

Public Class Methods

classes() click to toggle source
# File lib/osc_machete_rails/statusable.rb, line 63
def self.classes
  @classes ||= []
end
included(obj) click to toggle source
# File lib/osc_machete_rails/statusable.rb, line 27
def self.included(obj)
  # track the classes that include this module
  self.classes << Kernel.const_get(obj.name) unless obj.name.nil?

  # add class methods
  obj.send(:extend, ClassMethods)

  begin
    obj.class_eval do
      # Store job object info in a JSON column and replace old column methods
      if respond_to?(:table_exists?) && table_exists? && respond_to?(:column_names) && column_names.include?('job_cache')
        store :job_cache, accessors: [ :script, :pbsid, :host ], coder: JSON
        delegate :script_name, to: :job
        define_method :job_path do
          job.path
        end
      else
        define_method(:job_cache) do
          {
            script: (job_path && script_name) ? Pathname.new(job_path).join(script_name) : nil,
            pbsid: pbsid,
            host: nil
          }
        end
      end
    end
  rescue StandardError => e
    msg = "\nIf you are precompiling assets, you can ignore this:\n\tError thrown: #{e.inspect}"
    msg += "\n\tError thrown in OscMacheteRails::Statusable.included when trying to add job_cache to the class including Statusable: #{obj.name}."
    msg += "\n\tjob_cache method was not added to class." unless obj.method_defined? :job_cache
    msg += "\n\n"
    STDERR.puts msg
  end
end
update_status_of_all_active_jobs() click to toggle source

for each Statusable, call update_status! on active jobs

# File lib/osc_machete_rails/statusable.rb, line 68
def self.update_status_of_all_active_jobs
  # to eager load classes, set config.eager_load to true or execute Rails.application.eager_load!
  if self.classes.empty?
    Rails.logger.warn "Statusable.classes Array is empty. This should contain a list of all the classes that include Statusable. " \
      "This could occur if the Rails app is not configured to eager load classes."
  else
    Rails.logger.debug "Updating active job statuses via Statusable.update_status_of_all_active_jobs."
  end

  self.classes.each do |klass|
    klass.active.to_a.each(&:update_status!) if klass.respond_to?(:active)
  end
end

Public Instance Methods

job() click to toggle source

Returns associated OSC::Machete::Job instance

# File lib/osc_machete_rails/statusable.rb, line 123
def job
  OSC::Machete::Job.new(job_cache.symbolize_keys)
end
job=(new_job) click to toggle source

Setter that accepts an OSC::Machete::Job instance

@param [Job] new_job The Job object to be assigned to the Statusable instance.

# File lib/osc_machete_rails/statusable.rb, line 99
def job=(new_job)
  if self.has_attribute?(:job_cache)
    self.script = new_job.script_path.to_s
    self.pbsid = new_job.pbsid
    self.host = new_job.host if new_job.respond_to?(:host)
  else
    self.script_name = new_job.script_name
    self.job_path = new_job.path.to_s
    self.pbsid = new_job.pbsid
  end

  begin
    self.status = new_job.status
  rescue PBS::Error => e
    # a safe default
    self.status = OSC::Machete::Status.queued

    # log the error
    Rails.logger.error("After submitting the job with pbsid: #{pbsid}," \
                       " checking the status raised a PBS::Error: #{e.message}")
  end
end
results_valid?() click to toggle source

A hook that can be overidden with custom code also looks for default validation methods for existing WARNING: THIS USES ActiveSupport::Inflector methods underscore and parameterize

@return [Boolean] true if the results script is present

# File lib/osc_machete_rails/statusable.rb, line 144
def results_valid?
  valid = true

  if self.respond_to?(:script_name) && !script_name.nil?
    if self.respond_to?(results_validation_method_name)
      valid = self.send(results_validation_method_name)
    end
  end

  valid
end
results_validation_method_name() click to toggle source

Build the results validation method name from script_name attr using ActiveSupport methods

Call this using the Rails console to see what method you should implement to support results validation for that job.

@return [String] A string representing a validation method name from script_name attr using ActiveSupport methods

# File lib/osc_machete_rails/statusable.rb, line 135
def results_validation_method_name
  File.basename(script_name, ".*").underscore.parameterize(separator: '_') + "_results_valid?"
end
status() click to toggle source

getter returns a Status value from CHAR or a Status value

Calls superclass method
# File lib/osc_machete_rails/statusable.rb, line 14
def status
  OSC::Machete::Status.new(super)
end
status=(s) click to toggle source
Calls superclass method
# File lib/osc_machete_rails/statusable.rb, line 9
def status=(s)
  super(OSC::Machete::Status.new(s).char)
end
stop(update: true) click to toggle source

delete the batch job and update status may raise PBS::Error as it is unhandled here!

# File lib/osc_machete_rails/statusable.rb, line 20
def stop(update: true)
  return unless status.active?

  job.delete
  update(status: OSC::Machete::Status.failed) if update
end
update_status!(force: false) click to toggle source

FIXME: should have a unit test for this!

job.update_status! will update and save object
if submitted? and ! completed? and status changed from previous state
force will cause status to update regardless of completion status,
redoing the validations. This way, if you are fixing validation methods
you can use the Rails console to update the status of a Workflow by doing this:

    Container.last.jobs.each {|j| j.update_status!(force: true) }

Or for a single statusable such as job:

    job.update_status!(force: true)

FIXME: should log whether a validation method was called or
throw a warning that no validation method was found (the one that would have been called)

@param [Boolean, nil] force Force the update. (Default: false)
# File lib/osc_machete_rails/statusable.rb, line 173
def update_status!(force: false)
  # this will make it easier to differentiate from current_status
  cached_status = status

  # by default only update if its an active job
  if  (cached_status.not_submitted? && pbsid) || cached_status.active? || force
    # get the current status from the system
    current_status = job.status

    # if job is done, lets re-validate
    if current_status.completed?
      current_status = results_valid? ? OSC::Machete::Status.passed : OSC::Machete::Status.failed
    end

    if (current_status != cached_status) || force
      self.status = current_status
      self.save
    end
  end

rescue PBS::Error => e
  # we log the error but we just don't update the status
  Rails.logger.error("During update_status! call on job with pbsid #{pbsid} and id #{id}" \
                      " a PBS::Error was thrown: #{e.message}")
end