class Eventr::SupervisedObject

Attributes

on_exception[R]

Public Instance Methods

application() click to toggle source
# File lib/eventr/actors.rb, line 39
def application
  threads[:application]
end
on_exception=(&block) click to toggle source
# File lib/eventr/actors.rb, line 47
def on_exception=(&block) # rubocop:disable TrivialAccessors
  @on_exception = block
end
sleep_time_from_backoff() click to toggle source
# File lib/eventr/actors.rb, line 51
def sleep_time_from_backoff
  backoff = Thread.current[:backoff] || 0
  (0..backoff).inject([1, 0]) { |(a, b), _| [b, a + b] }[0]
end
start() click to toggle source
# File lib/eventr/actors.rb, line 30
def start
  start_application_thread
  start_supervisor_thread
end
start_application_thread() click to toggle source
# File lib/eventr/actors.rb, line 56
def start_application_thread
  threads[:application] ||= Thread.new do
    begin
      main
    rescue StandardError => e
      on_exception.call(e) if on_exception.respond_to? :call
      warn "#{e.class.name}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
      raise e
    ensure
      threads[:supervisor].wakeup # wakeup the supervisor to help us recover
    end
  end
end
start_supervisor_thread() click to toggle source
# File lib/eventr/actors.rb, line 70
def start_supervisor_thread # rubocop:disable MethodLength
  threads[:supervisor] ||= Thread.new do
    Thread.current[:backoff] = 1

    begin
      runs = 5
      loop do
        unless application && application.alive?
          puts "#{self.class.name}::Supervisor: cleaning up app thread and restarting it."
          threads[:application] = nil
          start_application_thread

          # stop when we've successfully cleaned something up
          runs = 0

          # and make sure to reset backoff
          Thread.current[:backoff] = 1
        end

        # check for required cleanup 5 times over as many seconds
        if (runs -= 1) <= 0
          Thread.stop
          runs = 5
        end

        sleep 1
      end

    rescue StandardError => e
      warn "#{e.class.name}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"

      if Thread.current[:backoff] <= 15
        Thread.current[:backoff] += 1
        sleep_time = sleep_time_from_backoff
        warn "sleeping for #{sleep_time} before restarting supervisor"
        sleep sleep_Time
        retry
      end

      # if the supervisor goes away, take the whole thing down.
      error_msg = "supervisor went away due to: #{e.class.name}: #{e.message} -> #{e.backtrace.first}"
      threads[:application].raise Error::SupervisorDown, error_msg

      raise e
    end
  end
end
stop() click to toggle source
# File lib/eventr/actors.rb, line 26
def stop
  threads.values.each { |t| t.send :kill }
end
supervisor() click to toggle source
# File lib/eventr/actors.rb, line 43
def supervisor
  threads[:supervisor]
end
threads() click to toggle source
# File lib/eventr/actors.rb, line 35
def threads
  @threads ||= {}
end