class ExceptionalSynchrony::EventMachineProxy

Constants

WRAP_WITH_ENSURE_COMPLETELY_SAFE

Attributes

connection[R]

Public Class Methods

new(proxy_class, connection_class) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 19
def initialize(proxy_class, connection_class)
  @proxy_class = proxy_class
  @synchrony = defined?(@proxy_class::Synchrony) ?  @proxy_class::Synchrony : @proxy_class
  @connection = connection_class

  proxy_class.error_handler do |error|
    ExceptionHandling.log_error(error, "ExceptionalSynchrony uncaught exception: ")
  end
end

Public Instance Methods

add_periodic_timer(*args, &block) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 37
def add_periodic_timer(*args, &block)
  @synchrony.add_periodic_timer(*args) do
    ensure_completely_safe("add_periodic_timer") do
      block.call
    end
  end
end
add_timer(seconds, &block) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 29
def add_timer(seconds, &block)
  @synchrony.add_timer(seconds) do
    ensure_completely_safe("add_timer") do
      block.call
    end
  end
end
connect(server, port = nil, handler = nil, *args, &block) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 73
def connect(server, port = nil, handler = nil, *args, &block)
  @proxy_class.connect(server, port, handler, *args, &block)
end
defer(context, wait_for_result: true, &block) click to toggle source

This method will execute the block on the background thread pool By default, it will block the caller until the background thread has finished, so that the result can be returned

:wait_for_result - setting this to false will prevent the caller from being blocked by this deferred work
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 92
def defer(context, wait_for_result: true, &block)
  if wait_for_result
    deferrable = EventMachine::DefaultDeferrable.new
    callback = -> (result) { deferrable.succeed(result) }

    EventMachine.defer(nil, callback) { CallbackExceptions.return_exception(&block) }
    EventMachine::Synchrony.sync(deferrable)
    CallbackExceptions.map_deferred_result(deferrable)
  else
    EventMachine.defer { ExceptionHandling.ensure_completely_safe("defer", &block) }
    nil
  end
end
defers_finished?() click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 69
def defers_finished?
  @proxy_class.defers_finished?
end
ensure_completely_safe(message) { || ... } click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 119
def ensure_completely_safe(message)
  if WRAP_WITH_ENSURE_COMPLETELY_SAFE
    ExceptionHandling.ensure_completely_safe(message) do
      yield
    end
  else
    yield
  end
end
next_tick(&block) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 55
def next_tick(&block)
  @synchrony.next_tick do
    ensure_completely_safe("next_tick") do
      block.call
    end
  end
end
reactor_running?() click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 106
def reactor_running?
  @proxy_class.reactor_running?
end
rescue_exceptions_and_ensure_exit(context) { || ... } click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 129
def rescue_exceptions_and_ensure_exit(context)
  yield
rescue StandardError => ex
  # Raise a non-StandardError so that not caught by EM.error_handler.
  # Expecting rescued exception to be stored in this new exception's cause.
  raise FatalRunError, "Fatal EventMachine #{context} error\n#{ex.class.name}: #{ex.message}"
end
run(on_error: :log, &block) click to toggle source

This method starts the EventMachine reactor. The on_error option has these possible values:

:log   - log any rescued StandardError exceptions and continue
:raise - raise FatalRunError for any rescued StandardError exceptions
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 81
def run(on_error: :log, &block)
  case on_error
  when :log   then run_with_error_logging(&block)
  when :raise then run_with_error_raising(&block)
  else raise ArgumentError, "Invalid on_error: #{on_error.inspect}, must be :log or :raise"
  end
end
run_and_stop() { || ... } click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 110
def run_and_stop
  ret = nil
  run do
    ret = yield
    stop
  end
  ret
end
sleep(seconds) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 45
def sleep(seconds)
  @synchrony.sleep(seconds)
end
stop() click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 63
def stop
  @proxy_class.stop
  @proxy_class.next_tick { } #Fake out EventMachine's epoll mechanism so we don't block until timers fire
  Thread.current.thread_variable_set(:em_synchrony_reactor_thread, false)
end
yield_to_reactor() click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 49
def yield_to_reactor
  if reactor_running?
    @synchrony.sleep(0)
  end
end

Private Instance Methods

run_with_error_logging(&block) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 139
def run_with_error_logging(&block)
  ensure_completely_safe("run_with_error_logging") do
    if @proxy_class.respond_to?(:synchrony)
      Thread.current.thread_variable_set(:em_synchrony_reactor_thread, true)
      @proxy_class.synchrony(&block)
    else
      @proxy_class.run(&block)
    end
  end
end
run_with_error_raising(&block) click to toggle source
# File lib/exceptional_synchrony/event_machine_proxy.rb, line 150
def run_with_error_raising(&block)
  run_block = -> { rescue_exceptions_and_ensure_exit("run_with_error_raising", &block) }

  rescue_exceptions_and_ensure_exit("run_with_error_raising") do
    if @proxy_class.respond_to?(:synchrony)
      Thread.current.thread_variable_set(:em_synchrony_reactor_thread, true)
      @proxy_class.synchrony(&run_block)
    else
      @proxy_class.run(&run_block)
    end
  end
end