module LyberCore::Robot

Attributes

check_queued_status[RW]
process[R]
workflow_name[R]

Public Class Methods

included(base) click to toggle source

Add the ClassMethods to the class this is being mixed into

# File lib/lyber_core/robot.rb, line 8
def self.included(base)
  base.extend ClassMethods
end
new(workflow_name, process, check_queued_status: true) click to toggle source
# File lib/lyber_core/robot.rb, line 24
def initialize(workflow_name, process, check_queued_status: true)
  Signal.trap('QUIT') { puts "#{Process.pid} ignoring SIGQUIT" } # SIGQUIT ignored to let the robot finish
  @workflow_name = workflow_name
  @process = process
  @check_queued_status = check_queued_status
end

Public Instance Methods

work(druid, context) click to toggle source

Sets up logging, timing and error handling of the job Calls the perform method, then sets workflow to 'completed' or 'error' depending on success rubocop:disable Metrics/AbcSize rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/PerceivedComplexity

# File lib/lyber_core/robot.rb, line 40
def work(druid, context)
  Honeybadger.context(druid: druid, process: process, workflow_name: workflow_name) if defined? Honeybadger
  workflow = workflow(druid)
  LyberCore::Log.set_logfile($stdout) # let process manager handle logging
  LyberCore::Log.info "#{druid} processing #{process} (#{workflow_name})"
  return if check_queued_status && !item_queued?(druid)

  # this is the default note to pass back to workflow service,
  # but it can be overriden by a robot that uses the Lybercore::Robot::ReturnState
  # object to return a status
  note = Socket.gethostname

  # update the workflow status to indicate that started
  workflow.start(note)

  result = nil
  elapsed = Benchmark.realtime do
    result = if method(:perform).arity == 1
      perform druid # implemented in the mixed-in robot class
    else
      perform druid, context
    end
  end

  # the final workflow state is determined by the return value of the perform step, if it is a ReturnState object,
  # we will use the defined status, otherwise default to completed
  # if a note is passed back, we will also use that instead of the default
  if result.class == LyberCore::Robot::ReturnState
    workflow_state = result.status
    note = result.note unless result.note.blank?
  else
    workflow_state = 'completed'
  end
  # update the workflow status from its current state to the state returned by perform (or 'completed' as the default)
  # noop allows a robot to not set a workflow as complete, e.g., if that is delegated to another service.
  workflow.complete(workflow_state, elapsed, note) unless workflow_state == 'noop'

  LyberCore::Log.info "Finished #{druid} in #{sprintf('%0.4f', elapsed)}s"
rescue StandardError => e
  Honeybadger.notify(e) if defined? Honeybadger
  begin
    LyberCore::Log.error e.message + "\n" + e.backtrace.join("\n")
    workflow.error(e.message, Socket.gethostname)
  rescue StandardError => e
    LyberCore::Log.error "Cannot set #{druid} to status='error'\n#{e.message}\n#{e.backtrace.join("\n")}"
    raise e # send exception to Resque failed queue
  end
end
workflow_service() click to toggle source
# File lib/lyber_core/robot.rb, line 31
def workflow_service
  raise 'The workflow_service method must be implemented on the class that includes LyberCore::Robot'
end

Private Instance Methods

item_queued?(druid) click to toggle source
# File lib/lyber_core/robot.rb, line 101
def item_queued?(druid)
  status = workflow_service.workflow_status(druid: druid,
                                            workflow: workflow_name,
                                            process: process)
  return true if status =~ /queued/i

  msg = "Item #{druid} is not queued for #{process} (#{workflow_name}), but has status of '#{status}'. Will skip processing"
  Honeybadger.notify(msg) if defined? Honeybadger
  LyberCore::Log.warn msg
  false
end
workflow(druid) click to toggle source

rubocop:enable Metrics/AbcSize rubocop:enable Metrics/CyclomaticComplexity rubocop:enable Metrics/PerceivedComplexity

# File lib/lyber_core/robot.rb, line 94
def workflow(druid)
  Workflow.new(workflow_service: workflow_service,
               druid: druid,
               workflow_name: workflow_name,
               process: process)
end