protobuf 2.0.0.rc3 → 2.0.0.rc4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/protobuf/cli.rb +1 -2
- data/lib/protobuf/{common/exceptions.rb → exceptions.rb} +0 -0
- data/lib/protobuf/field/base_field.rb +1 -1
- data/lib/protobuf/{common/logger.rb → logger.rb} +21 -0
- data/lib/protobuf/message/decoder.rb +2 -2
- data/lib/protobuf/message/encoder.rb +6 -4
- data/lib/protobuf/rpc/buffer.rb +2 -2
- data/lib/protobuf/rpc/client.rb +18 -18
- data/lib/protobuf/rpc/connectors/base.rb +3 -8
- data/lib/protobuf/rpc/connectors/common.rb +29 -28
- data/lib/protobuf/rpc/connectors/em_client.rb +9 -9
- data/lib/protobuf/rpc/connectors/eventmachine.rb +11 -9
- data/lib/protobuf/rpc/connectors/socket.rb +13 -17
- data/lib/protobuf/rpc/connectors/zmq.rb +13 -17
- data/lib/protobuf/rpc/error.rb +3 -3
- data/lib/protobuf/rpc/server.rb +41 -93
- data/lib/protobuf/rpc/servers/evented/server.rb +7 -9
- data/lib/protobuf/rpc/servers/evented_runner.rb +0 -11
- data/lib/protobuf/rpc/servers/socket/server.rb +8 -7
- data/lib/protobuf/rpc/servers/socket/worker.rb +22 -15
- data/lib/protobuf/rpc/servers/zmq/server.rb +3 -3
- data/lib/protobuf/rpc/servers/zmq/util.rb +1 -1
- data/lib/protobuf/rpc/servers/zmq/worker.rb +6 -15
- data/lib/protobuf/rpc/service.rb +145 -228
- data/lib/protobuf/rpc/service_dispatcher.rb +114 -0
- data/lib/protobuf/rpc/stat.rb +46 -33
- data/lib/protobuf/version.rb +1 -1
- data/lib/protobuf/{common/wire_type.rb → wire_type.rb} +0 -0
- data/spec/benchmark/tasks.rb +18 -18
- data/spec/functional/evented_server_spec.rb +3 -4
- data/spec/functional/socket_server_spec.rb +3 -3
- data/spec/functional/zmq_server_spec.rb +3 -3
- data/spec/lib/protobuf/{common/logger_spec.rb → logger_spec.rb} +46 -36
- data/spec/lib/protobuf/rpc/client_spec.rb +10 -58
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +1 -39
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +3 -6
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +0 -12
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +1 -6
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +94 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +132 -45
- data/spec/spec_helper.rb +4 -3
- data/spec/support/server.rb +8 -4
- metadata +41 -35
data/lib/protobuf/cli.rb
CHANGED
File without changes
|
@@ -53,13 +53,34 @@ module Protobuf
|
|
53
53
|
module LogMethods
|
54
54
|
[:debug, :info, :warn, :error, :fatal, :any, :add, :log].each do |m|
|
55
55
|
define_method("log_#{m}") do |*params, &block|
|
56
|
+
params.map! { |message| sign_message(message) }
|
56
57
|
Protobuf::Logger.__send__(m, *params, &block)
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
61
|
+
# When included, also extend the LogMethods module for class access.
|
60
62
|
def self.included(base)
|
61
63
|
base.extend(LogMethods)
|
62
64
|
end
|
65
|
+
|
66
|
+
# We often want to log an exception, so let's make that a core
|
67
|
+
# concern of the logger.
|
68
|
+
#
|
69
|
+
def log_exception(ex)
|
70
|
+
log_error { ex.message }
|
71
|
+
log_error { ex.backtrace[0..5].join("\n") }
|
72
|
+
log_debug { ex.backtrace.join("\n") }
|
73
|
+
end
|
74
|
+
|
75
|
+
def log_signature
|
76
|
+
@_log_signature ||= "[#{self.class == Class ? self.name : self.class.name}]"
|
77
|
+
end
|
78
|
+
|
79
|
+
def sign_message(message)
|
80
|
+
"#{log_signature} #{message}"
|
81
|
+
end
|
82
|
+
|
63
83
|
end
|
84
|
+
|
64
85
|
end
|
65
86
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'protobuf/
|
2
|
-
require 'protobuf/
|
1
|
+
require 'protobuf/wire_type'
|
2
|
+
require 'protobuf/exceptions'
|
3
3
|
|
4
4
|
module Protobuf
|
5
5
|
|
@@ -10,8 +10,10 @@ module Protobuf
|
|
10
10
|
# Encode +message+ and write to +stream+.
|
11
11
|
def encode(stream, message)
|
12
12
|
# FIXME make this not as ghetto
|
13
|
-
|
14
|
-
|
13
|
+
unless message.initialized?
|
14
|
+
raise NotInitializedError, "Message #{message.class.name} is not initialized (one or more fields is improperly set): #{JSON.parse(message.to_json)}"
|
15
|
+
end
|
16
|
+
|
15
17
|
message.each_field do |field, value|
|
16
18
|
next unless message.has_field?(field.name)
|
17
19
|
|
data/lib/protobuf/rpc/buffer.rb
CHANGED
@@ -32,7 +32,7 @@ module Protobuf
|
|
32
32
|
end
|
33
33
|
|
34
34
|
@size = @data.length
|
35
|
-
|
35
|
+
"#{@size}-#{@data}"
|
36
36
|
end
|
37
37
|
|
38
38
|
def <<(data)
|
@@ -63,7 +63,7 @@ module Protobuf
|
|
63
63
|
def get_data_size
|
64
64
|
if @size == 0 || @data.match(SIZE_REGEX)
|
65
65
|
sliced_size = @data.slice!(SIZE_REGEX)
|
66
|
-
@size = sliced_size.gsub('-', '').to_i unless
|
66
|
+
@size = sliced_size.gsub('-', '').to_i unless sliced_size.nil?
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
data/lib/protobuf/rpc/client.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'protobuf'
|
3
|
-
require 'protobuf/
|
3
|
+
require 'protobuf/logger'
|
4
4
|
require 'protobuf/rpc/error'
|
5
5
|
require 'protobuf/rpc/connector'
|
6
6
|
|
@@ -10,7 +10,7 @@ module Protobuf
|
|
10
10
|
extend Forwardable
|
11
11
|
include Protobuf::Logger::LogMethods
|
12
12
|
|
13
|
-
delegate [:options, :complete_cb, :success_cb, :failure_cb
|
13
|
+
delegate [:options, :complete_cb, :success_cb, :failure_cb] => :@connector
|
14
14
|
attr_reader :connector
|
15
15
|
|
16
16
|
# Create a new client with default options (defined in ClientConnection)
|
@@ -29,15 +29,14 @@ module Protobuf
|
|
29
29
|
def initialize(opts={})
|
30
30
|
raise "Invalid client configuration. Service must be defined." if opts[:service].nil?
|
31
31
|
@connector = Connector.connector_for_client.new(opts)
|
32
|
-
log_debug { "
|
32
|
+
log_debug { sign_message("Initialized with options: #{opts.inspect}") }
|
33
33
|
end
|
34
34
|
|
35
35
|
def log_signature
|
36
|
-
@
|
36
|
+
@_log_signature ||= "client-#{self.class}"
|
37
37
|
end
|
38
38
|
|
39
39
|
# Set a complete callback on the client to return the object (self).
|
40
|
-
# Callback is called regardless of :async setting.
|
41
40
|
#
|
42
41
|
# client = Client.new(:service => WidgetService)
|
43
42
|
# client.on_complete {|obj| ... }
|
@@ -57,7 +56,6 @@ module Protobuf
|
|
57
56
|
# Set a failure callback on the client to return the
|
58
57
|
# error returned by the service, if any. If this callback
|
59
58
|
# is called, success_cb will NOT be called.
|
60
|
-
# Callback is called regardless of :async setting.
|
61
59
|
#
|
62
60
|
# client = Client.new(:service => WidgetService)
|
63
61
|
# client.on_failure {|err| ... }
|
@@ -68,7 +66,7 @@ module Protobuf
|
|
68
66
|
|
69
67
|
def on_failure=(callable)
|
70
68
|
if callable != nil && !callable.respond_to?(:call) && callable.arity != 1
|
71
|
-
raise "
|
69
|
+
raise "Callable must take a single argument and respond to :call"
|
72
70
|
end
|
73
71
|
|
74
72
|
@connector.failure_cb = callable
|
@@ -77,7 +75,6 @@ module Protobuf
|
|
77
75
|
# Set a success callback on the client to return the
|
78
76
|
# successful response from the service when it is returned.
|
79
77
|
# If this callback is called, failure_cb will NOT be called.
|
80
|
-
# Callback is called regardless of :async setting.
|
81
78
|
#
|
82
79
|
# client = Client.new(:service => WidgetService)
|
83
80
|
# client.on_success {|res| ... }
|
@@ -88,7 +85,7 @@ module Protobuf
|
|
88
85
|
|
89
86
|
def on_success=(callable)
|
90
87
|
if callable != nil && !callable.respond_to?(:call) && callable.arity != 1
|
91
|
-
raise "
|
88
|
+
raise "Callable must take a single argument and respond to :call"
|
92
89
|
end
|
93
90
|
|
94
91
|
@connector.success_cb = callable
|
@@ -108,26 +105,29 @@ module Protobuf
|
|
108
105
|
#
|
109
106
|
def method_missing(method, *params)
|
110
107
|
service = options[:service]
|
111
|
-
unless service.
|
112
|
-
log_error { "
|
108
|
+
unless service.rpc_method?(method)
|
109
|
+
log_error { sign_message("#{service.name}##{method.to_s} not rpc method, passing to super") }
|
113
110
|
super(method, *params)
|
114
111
|
else
|
115
|
-
log_debug { "
|
116
|
-
rpc = service.rpcs[
|
112
|
+
log_debug { sign_message("#{service.name}##{method.to_s}") }
|
113
|
+
rpc = service.rpcs[method.to_sym]
|
114
|
+
|
117
115
|
options[:request_type] = rpc.request_type
|
118
|
-
log_debug { "
|
116
|
+
log_debug { sign_message("Request Type: #{options[:request_type].name}") }
|
117
|
+
|
119
118
|
options[:response_type] = rpc.response_type
|
120
|
-
log_debug { "
|
119
|
+
log_debug { sign_message("Response Type: #{options[:response_type].name}") }
|
120
|
+
|
121
121
|
options[:method] = method.to_s
|
122
122
|
options[:request] = params[0].is_a?(Hash) ? options[:request_type].new(params[0]) : params[0]
|
123
|
-
log_debug { "
|
123
|
+
log_debug { sign_message("Request Data: #{options[:request].inspect}") }
|
124
124
|
|
125
125
|
# Call client to setup on_success and on_failure event callbacks
|
126
126
|
if block_given?
|
127
|
-
log_debug { "
|
127
|
+
log_debug { sign_message("client setup callback given, invoking") }
|
128
128
|
yield(self)
|
129
129
|
else
|
130
|
-
log_debug { "
|
130
|
+
log_debug { sign_message("no block given for callbacks") }
|
131
131
|
end
|
132
132
|
|
133
133
|
send_request
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'protobuf/
|
1
|
+
require 'protobuf/logger'
|
2
2
|
require 'protobuf/rpc/rpc.pb'
|
3
3
|
require 'protobuf/rpc/buffer'
|
4
4
|
require 'protobuf/rpc/error'
|
@@ -16,27 +16,22 @@ module Protobuf
|
|
16
16
|
:request => nil, # The request object sent by the client
|
17
17
|
:request_type => nil, # The request type expected by the client
|
18
18
|
:response_type => nil, # The response type expected by the client
|
19
|
-
:async => false, # Whether or not to block a client call, this is actually handled by client.rb
|
20
19
|
:timeout => 30 # The default timeout for the request, also handled by client.rb
|
21
20
|
}
|
22
21
|
|
23
22
|
class Base
|
24
23
|
include Protobuf::Logger::LogMethods
|
25
|
-
|
24
|
+
|
26
25
|
attr_reader :options
|
27
26
|
attr_accessor :success_cb, :failure_cb, :complete_cb
|
28
27
|
|
29
28
|
def initialize(options)
|
30
29
|
@options = DEFAULT_OPTIONS.merge(options)
|
31
30
|
end
|
32
|
-
|
31
|
+
|
33
32
|
def send_request
|
34
33
|
raise 'If you inherit a Connector from Base you must implement send_request'
|
35
34
|
end
|
36
|
-
|
37
|
-
def async?
|
38
|
-
!!@options[:async]
|
39
|
-
end
|
40
35
|
end
|
41
36
|
end
|
42
37
|
end
|
@@ -12,23 +12,23 @@ module Protobuf
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def complete
|
15
|
-
@stats.
|
16
|
-
@stats.
|
17
|
-
log_debug {
|
15
|
+
@stats.stop
|
16
|
+
log_info { @stats.to_s }
|
17
|
+
log_debug { sign_message('Response proceessing complete') }
|
18
18
|
@complete_cb.call(self) unless @complete_cb.nil?
|
19
|
-
rescue
|
20
|
-
log_error {
|
21
|
-
|
19
|
+
rescue => e
|
20
|
+
log_error { sign_message('Complete callback error encountered') }
|
21
|
+
log_exception(e)
|
22
22
|
raise
|
23
23
|
end
|
24
24
|
|
25
25
|
def data_callback(data)
|
26
|
-
log_debug {
|
26
|
+
log_debug { sign_message('Using data_callback') }
|
27
27
|
@used_data_callback = true
|
28
28
|
@data = data
|
29
29
|
end
|
30
30
|
|
31
|
-
# All failures should be routed through this method
|
31
|
+
# All failures should be routed through this method.
|
32
32
|
#
|
33
33
|
# @param [Symbol] code The code we're using (see ::Protobuf::Socketrpc::ErrorReason)
|
34
34
|
# @param [String] message The error message
|
@@ -36,35 +36,36 @@ module Protobuf
|
|
36
36
|
@error = ClientError.new
|
37
37
|
@error.code = code.is_a?(Symbol) ? Protobuf::Socketrpc::ErrorReason.values[code] : code
|
38
38
|
@error.message = message
|
39
|
-
log_debug { "
|
39
|
+
log_debug { sign_message("Server failed request (invoking on_failure): #{@error.inspect}") }
|
40
40
|
|
41
41
|
@failure_cb.call(@error) unless @failure_cb.nil?
|
42
|
-
rescue
|
43
|
-
log_error { "
|
44
|
-
|
42
|
+
rescue => e
|
43
|
+
log_error { sign_message("Failure callback error encountered") }
|
44
|
+
log_exception(e)
|
45
45
|
raise
|
46
46
|
ensure
|
47
47
|
complete
|
48
48
|
end
|
49
49
|
|
50
50
|
def initialize_stats
|
51
|
-
@stats = Protobuf::Rpc::Stat.new(:CLIENT
|
51
|
+
@stats = Protobuf::Rpc::Stat.new(:CLIENT)
|
52
52
|
@stats.server = [@options[:port], @options[:host]]
|
53
53
|
@stats.service = @options[:service].name
|
54
54
|
@stats.method = @options[:method].to_s
|
55
55
|
rescue => ex
|
56
|
+
log_exception(ex)
|
56
57
|
fail(:RPC_ERROR, "Invalid stats configuration. #{ex.message}")
|
57
58
|
end
|
58
59
|
|
59
60
|
def log_signature
|
60
|
-
@
|
61
|
+
@_log_signature ||= "client-#{self.class}"
|
61
62
|
end
|
62
63
|
|
63
64
|
def parse_response
|
64
65
|
# Close up the connection as we no longer need it
|
65
66
|
close_connection
|
66
67
|
|
67
|
-
log_debug { "
|
68
|
+
log_debug { sign_message("Parsing response from server (connection closed)") }
|
68
69
|
|
69
70
|
# Parse out the raw response
|
70
71
|
response_wrapper = Protobuf::Socketrpc::Response.new
|
@@ -72,13 +73,13 @@ module Protobuf
|
|
72
73
|
|
73
74
|
# Determine success or failure based on parsed data
|
74
75
|
if response_wrapper.has_field?(:error_reason)
|
75
|
-
log_debug { "
|
76
|
+
log_debug { sign_message("Error response parsed") }
|
76
77
|
|
77
78
|
# fail the call if we already know the client is failed
|
78
79
|
# (don't try to parse out the response payload)
|
79
80
|
fail(response_wrapper.error_reason, response_wrapper.error)
|
80
81
|
else
|
81
|
-
log_debug { "
|
82
|
+
log_debug { sign_message("Successful response parsed") }
|
82
83
|
|
83
84
|
# Ensure client_response is an instance
|
84
85
|
response_type = @options[:response_type].new
|
@@ -96,8 +97,8 @@ module Protobuf
|
|
96
97
|
|
97
98
|
def post_init
|
98
99
|
send_data unless error?
|
99
|
-
rescue
|
100
|
-
fail(:RPC_ERROR,
|
100
|
+
rescue => e
|
101
|
+
fail(:RPC_ERROR, "Connection error: #{e.message}")
|
101
102
|
end
|
102
103
|
|
103
104
|
def rpc_request_data
|
@@ -108,8 +109,8 @@ module Protobuf
|
|
108
109
|
:method_name => @options[:method].to_s,
|
109
110
|
:request_proto => @options[:request].serialize_to_string
|
110
111
|
).serialize_to_string
|
111
|
-
rescue
|
112
|
-
fail
|
112
|
+
rescue => e
|
113
|
+
fail(:INVALID_REQUEST_PROTO, "Could not set request proto: #{e.message}")
|
113
114
|
end
|
114
115
|
|
115
116
|
def setup_connection
|
@@ -118,12 +119,12 @@ module Protobuf
|
|
118
119
|
end
|
119
120
|
|
120
121
|
def succeed(response)
|
121
|
-
log_debug { "
|
122
|
+
log_debug { sign_message("Server succeeded request (invoking on_success)") }
|
122
123
|
@success_cb.call(response) unless @success_cb.nil?
|
123
|
-
rescue
|
124
|
-
log_error { "
|
125
|
-
|
126
|
-
fail
|
124
|
+
rescue => e
|
125
|
+
log_error { sign_message("Success callback error encountered") }
|
126
|
+
log_exception(e)
|
127
|
+
fail(:RPC_ERROR, "An exception occurred while calling on_success: #{e.message}")
|
127
128
|
ensure
|
128
129
|
complete
|
129
130
|
end
|
@@ -132,13 +133,13 @@ module Protobuf
|
|
132
133
|
unless @options[:request].class == @options[:request_type]
|
133
134
|
expected = @options[:request_type].name
|
134
135
|
actual = @options[:request].class.name
|
135
|
-
fail
|
136
|
+
fail(:INVALID_REQUEST_PROTO, "Expected request type to be type of #{expected}, got #{actual} instead")
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
139
140
|
def verify_callbacks
|
140
141
|
if !any_callbacks?
|
141
|
-
log_debug { "
|
142
|
+
log_debug { sign_message("No callbacks set, using data_callback") }
|
142
143
|
@success_cb = @failure_cb = self.method(:data_callback)
|
143
144
|
end
|
144
145
|
end
|
@@ -19,9 +19,9 @@ module Protobuf
|
|
19
19
|
@response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
|
20
20
|
verify_options
|
21
21
|
|
22
|
-
log_debug { "
|
23
|
-
rescue
|
24
|
-
fail(:RPC_ERROR,
|
22
|
+
log_debug { sign_message("Client Initialized: #{options.inspect}") }
|
23
|
+
rescue => e
|
24
|
+
fail(:RPC_ERROR, "Failed to initialize connection: #{e.message}")
|
25
25
|
end
|
26
26
|
|
27
27
|
##
|
@@ -29,7 +29,7 @@ module Protobuf
|
|
29
29
|
#
|
30
30
|
def self.connect(options={})
|
31
31
|
options = DEFAULT_OPTIONS.merge(options)
|
32
|
-
log_debug { "
|
32
|
+
log_debug { sign_message("Connecting to server: #{options.inspect}") }
|
33
33
|
EM.connect(options[:host], options[:port], self, options)
|
34
34
|
end
|
35
35
|
|
@@ -56,19 +56,19 @@ module Protobuf
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def receive_data(data)
|
59
|
-
log_debug { "
|
59
|
+
log_debug { sign_message("receive_data: #{data}") }
|
60
60
|
@response_buffer << data
|
61
61
|
@response_data = @response_buffer.data
|
62
|
-
parse_response if
|
62
|
+
parse_response if !@response_data.nil? && @response_buffer.flushed?
|
63
63
|
end
|
64
64
|
|
65
65
|
def send_data
|
66
66
|
request_buffer = ::Protobuf::Rpc::Buffer.new(:write)
|
67
67
|
request_buffer.set_data(@request_data)
|
68
|
-
log_debug { "
|
68
|
+
log_debug { sign_message("sending data: #{request_buffer.inspect}") }
|
69
69
|
super(request_buffer.write)
|
70
|
-
rescue
|
71
|
-
fail(:RPC_ERROR,
|
70
|
+
rescue => e
|
71
|
+
fail(:RPC_ERROR, "Connection error: #{e.message}")
|
72
72
|
end
|
73
73
|
|
74
74
|
# overwriting this method for java because it's broken in eventmachine. See https://github.com/eventmachine/eventmachine/issues/14
|
@@ -11,17 +11,17 @@ module Protobuf
|
|
11
11
|
f = Fiber.current
|
12
12
|
|
13
13
|
::EM.next_tick do
|
14
|
-
log_debug {
|
14
|
+
log_debug { sign_message('Scheduling EventMachine client request to be created on next tick') }
|
15
15
|
cnxn = EMClient.connect(options, &ensure_cb)
|
16
16
|
cnxn.on_success(&success_cb) if success_cb
|
17
17
|
cnxn.on_failure(&ensure_cb)
|
18
|
-
cnxn.on_complete { resume_fiber(f) }
|
18
|
+
cnxn.on_complete { resume_fiber(f) }
|
19
19
|
cnxn.setup_connection
|
20
20
|
cnxn.send_data
|
21
|
-
log_debug {
|
21
|
+
log_debug { sign_message('Connection scheduled') }
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
set_timeout_and_validate_fiber
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -32,11 +32,11 @@ module Protobuf
|
|
32
32
|
# don't want to swallow the black holes.
|
33
33
|
#
|
34
34
|
def ensure_cb
|
35
|
-
@ensure_cb ||= (@failure_cb || lambda { |error| raise
|
35
|
+
@ensure_cb ||= (@failure_cb || lambda { |error| raise "#{error.code.name}: #{error.message}" })
|
36
36
|
end
|
37
37
|
|
38
38
|
def log_signature
|
39
|
-
@
|
39
|
+
@_log_signature ||= "client-#{self.class}"
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
@@ -58,18 +58,20 @@ module Protobuf
|
|
58
58
|
::EM::cancel_timer(@timeout_timer)
|
59
59
|
fib.resume(true)
|
60
60
|
rescue => ex
|
61
|
-
|
61
|
+
log_exception(ex)
|
62
|
+
message = "Synchronous client failed: #{ex.message}"
|
62
63
|
error_stop_reactor(message)
|
63
64
|
end
|
64
65
|
|
65
66
|
def set_timeout_and_validate_fiber
|
66
67
|
@timeout_timer = ::EM::add_timer(@options[:timeout]) do
|
67
|
-
message =
|
68
|
+
message = "Client timeout of #{@options[:timeout]} seconds expired"
|
68
69
|
error_stop_reactor(message)
|
69
70
|
end
|
70
71
|
|
71
72
|
Fiber.yield
|
72
|
-
rescue FiberError
|
73
|
+
rescue FiberError => ex
|
74
|
+
log_exception(ex)
|
73
75
|
message = "Synchronous calls must be in 'EM.fiber_run' block"
|
74
76
|
error_stop_reactor(message)
|
75
77
|
end
|