Module: OscMacheteRails::Statusable

Defined in:
lib/osc_machete_rails/statusable.rb

Overview

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

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.classesObject



63
64
65
# File 'lib/osc_machete_rails/statusable.rb', line 63

def self.classes
  @classes ||= []
end

.included(obj) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 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_jobsObject

for each Statusable, call update_status! on active jobs



68
69
70
71
72
73
74
75
76
77
78
79
80
# 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

Instance Method Details

#jobObject

Returns associated OSC::Machete::Job instance



123
124
125
# File 'lib/osc_machete_rails/statusable.rb', line 123

def job
  OSC::Machete::Job.new(job_cache.symbolize_keys)
end

#job=(new_job) ⇒ Object

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

Parameters:

  • new_job (Job)

    The Job object to be assigned to the Statusable instance.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# 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?Boolean

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

Returns:

  • (Boolean)

    true if the results script is present



144
145
146
147
148
149
150
151
152
153
154
# 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_nameString

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.

using ActiveSupport methods

Returns:

  • (String)

    A string representing a validation method name from script_name attr



135
136
137
# File 'lib/osc_machete_rails/statusable.rb', line 135

def results_validation_method_name
  File.basename(script_name, ".*").underscore.parameterize(separator: '_') + "_results_valid?"
end

#statusObject

getter returns a Status value from CHAR or a Status value



14
15
16
# File 'lib/osc_machete_rails/statusable.rb', line 14

def status
  OSC::Machete::Status.new(super)
end

#status=(s) ⇒ Object



9
10
11
# File 'lib/osc_machete_rails/statusable.rb', line 9

def status=(s)
  super(OSC::Machete::Status.new(s).char)
end

#stop(update: true) ⇒ Object

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



20
21
22
23
24
25
# 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) ⇒ Object

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)

Parameters:

  • force (Boolean, nil) (defaults to: false)

    Force the update. (Default: false)



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# 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. && 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