class Crabfarm::Engines::AsyncStateManager

Public Class Methods

new(_context) click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 9
def initialize(_context)
  @context = _context
  @working = false
  @fatal = nil
  @lock = Mutex.new
end

Public Instance Methods

navigate(_name, _params={}, _wait=nil) click to toggle source
restart() click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 35
def restart
  stop
  start
end
start() click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 16
def start
  @lock.synchronize {
    if @thread.nil?
      @fatal = nil
      @thread = Thread.new { crawl_loop }
    end
  }
end
stop() click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 25
def stop
  @lock.synchronize {
    unless @thread.nil?
      @thread.raise LoopAbortedException
      @thread.join
      @thread = nil
    end
  }
end
wait_for_state(_wait=nil) click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 59
def wait_for_state(_wait=nil)
  @lock.synchronize {
    wait_and_load_struct _wait
  }
end

Private Instance Methods

crawl_loop() click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 102
def crawl_loop
  begin
    loop do
      if @working
        begin
          logger.info "Transitioning state: #{@next_state_name}"
          ActiveSupport::Dependencies.clear if defined? ActiveSupport::Dependencies
          ts = TransitionService.transition(@context, @next_state_name, @next_state_params)
          @elapsed = ts.elapsed
          @doc = ts.document
          @error = nil

          logger.info "Transitioned in #{@elapsed.real}"
        rescue Exception => e
          @doc = nil
          @error = e

          logger.error "Error during transition:"
          logger.error e
        end

        @lock.synchronize {
          @state_name = @next_state_name
          @state_params = @next_state_params
          @working = false
        }
      else sleep 0.2 end
    end
  rescue LoopAbortedException
    logger.info "Manager stopping"

  rescue Exception => e
    logger.fatal "Unhandled exception:"
    logger.fatal e

    @lock.synchronize {
      @fatal = e
    }
  end
end
logger() click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 143
def logger
  Crabfarm.logger
end
matches_current_state?(_name, _params) click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 67
def matches_current_state?(_name, _params)
  _name == @state_name and _params == @state_params
end
matches_next_state?(_name, _params) click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 71
def matches_next_state?(_name, _params)
  _name == @next_state_name and _params == @next_state_params
end
state_as_struct() click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 90
def state_as_struct
  raise CrawlerError.new @fatal if @fatal
  raise CrawlerError.new @error if @error

  OpenStruct.new({
    name: @state_name,
    params: @state_params,
    doc: @doc,
    elapsed: @elapsed
  })
end
wait_and_load_struct(_wait) click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 75
def wait_and_load_struct(_wait)
  # need to use this method because mutex are not reentrant and monitors are slow.
  wait_while_working _wait unless _wait.nil?
  raise TimeoutError.new if @working
  state_as_struct
end
wait_while_working(_wait) click to toggle source
# File lib/crabfarm/engines/async_state_manager.rb, line 82
def wait_while_working(_wait)
  # TODO: use condition variables instead of wait loops
  start = Time.now
  while @working and Time.now - start < _wait.seconds
    @lock.sleep 0.25
  end
end