Class: ExceptionalSynchrony::EventMachineProxy

Inherits:
Object
  • Object
show all
Defined in:
lib/exceptional_synchrony/event_machine_proxy.rb

Constant Summary collapse

WRAP_WITH_ENSURE_COMPLETELY_SAFE =
(ENV['RACK_ENV'] != 'test')

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(proxy_class, connection_class) ⇒ EventMachineProxy

Returns a new instance of EventMachineProxy.



19
20
21
22
23
24
25
26
27
# 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

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



15
16
17
# File 'lib/exceptional_synchrony/event_machine_proxy.rb', line 15

def connection
  @connection
end

Instance Method Details

#add_periodic_timer(*args, &block) ⇒ Object



37
38
39
40
41
42
43
# 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) ⇒ Object



29
30
31
32
33
34
35
# 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) ⇒ Object



73
74
75
# 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 = nil, wait_for_result: true, &block) ⇒ Object

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


92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/exceptional_synchrony/event_machine_proxy.rb', line 92

def defer(_context = nil, 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?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/exceptional_synchrony/event_machine_proxy.rb', line 69

def defers_finished?
  @proxy_class.defers_finished?
end

#ensure_completely_safe(message) ⇒ Object



119
120
121
122
123
124
125
126
127
# 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) ⇒ Object



55
56
57
58
59
60
61
# 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?Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/exceptional_synchrony/event_machine_proxy.rb', line 106

def reactor_running?
  @proxy_class.reactor_running?
end

#rescue_exceptions_and_ensure_exit(context) ⇒ Object



129
130
131
132
133
134
135
# 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) ⇒ Object

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


81
82
83
84
85
86
87
# 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_stopObject



110
111
112
113
114
115
116
117
# 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) ⇒ Object



45
46
47
# File 'lib/exceptional_synchrony/event_machine_proxy.rb', line 45

def sleep(seconds)
  @synchrony.sleep(seconds)
end

#stopObject



63
64
65
66
67
# 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_reactorObject



49
50
51
52
53
# File 'lib/exceptional_synchrony/event_machine_proxy.rb', line 49

def yield_to_reactor
  if reactor_running?
    @synchrony.sleep(0)
  end
end