protobuf 3.2.1 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/protobuf/cli.rb +17 -13
- data/lib/protobuf/field/base_field.rb +3 -1
- data/lib/protobuf/field/bytes_field.rb +2 -2
- data/lib/protobuf/lifecycle.rb +1 -1
- data/lib/protobuf/logging.rb +49 -0
- data/lib/protobuf/rpc/client.rb +10 -10
- data/lib/protobuf/rpc/connectors/base.rb +2 -2
- data/lib/protobuf/rpc/connectors/common.rb +12 -12
- data/lib/protobuf/rpc/connectors/socket.rb +6 -6
- data/lib/protobuf/rpc/connectors/zmq.rb +11 -9
- data/lib/protobuf/rpc/middleware/exception_handler.rb +1 -1
- data/lib/protobuf/rpc/middleware/logger.rb +1 -1
- data/lib/protobuf/rpc/middleware/request_decoder.rb +3 -3
- data/lib/protobuf/rpc/middleware/response_encoder.rb +3 -3
- data/lib/protobuf/rpc/server.rb +1 -1
- data/lib/protobuf/rpc/servers/socket/server.rb +7 -7
- data/lib/protobuf/rpc/servers/socket/worker.rb +2 -2
- data/lib/protobuf/rpc/servers/zmq/broker.rb +9 -5
- 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_runner.rb +4 -4
- data/lib/protobuf/rpc/service.rb +2 -2
- data/lib/protobuf/rpc/service_directory.rb +8 -8
- data/lib/protobuf/rpc/service_dispatcher.rb +2 -2
- data/lib/protobuf/rpc/stat.rb +1 -1
- data/lib/protobuf/version.rb +1 -1
- data/spec/benchmark/tasks.rb +2 -2
- data/spec/lib/protobuf/cli_spec.rb +9 -3
- data/spec/spec_helper.rb +6 -5
- data/spec/support/server.rb +3 -3
- metadata +64 -106
- checksums.yaml +0 -7
- data/lib/protobuf/logger.rb +0 -86
- data/spec/lib/protobuf/logger_spec.rb +0 -136
data/lib/protobuf/cli.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'protobuf/version'
|
3
|
-
require 'protobuf/
|
3
|
+
require 'protobuf/logging'
|
4
4
|
require 'protobuf/rpc/servers/socket_runner'
|
5
5
|
require 'protobuf/rpc/servers/zmq_runner'
|
6
6
|
|
7
7
|
module Protobuf
|
8
8
|
class CLI < ::Thor
|
9
9
|
include ::Thor::Actions
|
10
|
+
include ::Protobuf::Logging
|
10
11
|
|
11
12
|
attr_accessor :runner, :mode
|
12
13
|
|
@@ -21,7 +22,7 @@ module Protobuf
|
|
21
22
|
option :threshold, :type => :numeric, :default => 100, :aliases => %w(-t), :desc => 'Multi-threaded Socket Server cleanup threshold.'
|
22
23
|
option :threads, :type => :numeric, :default => 5, :aliases => %w(-r), :desc => 'Number of worker threads to run. Only applicable in --zmq mode.'
|
23
24
|
|
24
|
-
option :log, :type => :string, :aliases => %w(-l), :desc => 'Log file or device. Default is STDOUT.'
|
25
|
+
option :log, :type => :string, :default => STDOUT, :aliases => %w(-l), :desc => 'Log file or device. Default is STDOUT.'
|
25
26
|
option :level, :type => :numeric, :default => ::Logger::INFO, :aliases => %w(-v), :desc => 'Log level to use, 0-5 (see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/)'
|
26
27
|
|
27
28
|
option :socket, :type => :boolean, :aliases => %w(-s), :desc => 'Socket Mode for server and client connections.'
|
@@ -86,12 +87,14 @@ module Protobuf
|
|
86
87
|
# Setup the protobuf logger.
|
87
88
|
def configure_logger
|
88
89
|
debug_say('Configuring logger')
|
89
|
-
|
90
|
-
|
90
|
+
|
91
|
+
log_level = options.debug? ? ::Logger::DEBUG : options.level
|
92
|
+
|
93
|
+
::Protobuf::Logging.initialize_logger(options.log, log_level)
|
91
94
|
|
92
95
|
# Debug output the server options to the log file.
|
93
|
-
|
94
|
-
|
96
|
+
logger.debug { 'Debugging options:' }
|
97
|
+
logger.debug { options.inspect }
|
95
98
|
end
|
96
99
|
|
97
100
|
# Re-write the $0 var to have a nice process name in ps.
|
@@ -185,15 +188,16 @@ module Protobuf
|
|
185
188
|
end
|
186
189
|
|
187
190
|
def say_and_exit(message, exception = nil)
|
188
|
-
message = set_color(message, :red) if
|
191
|
+
message = set_color(message, :red) if options.log == STDOUT
|
192
|
+
|
193
|
+
logger.error { message }
|
189
194
|
|
190
|
-
::Protobuf::Logger.error { message }
|
191
195
|
if exception
|
192
196
|
$stderr.puts "[#{exception.class.name}] #{exception.message}"
|
193
197
|
$stderr.puts exception.backtrace.join("\n")
|
194
198
|
|
195
|
-
|
196
|
-
|
199
|
+
logger.error { "[#{exception.class.name}] #{exception.message}" }
|
200
|
+
logger.debug { exception.backtrace.join("\n") }
|
197
201
|
end
|
198
202
|
|
199
203
|
exit(1)
|
@@ -212,10 +216,10 @@ module Protobuf
|
|
212
216
|
end
|
213
217
|
|
214
218
|
def shutdown_server
|
215
|
-
|
219
|
+
logger.info { 'RPC Server shutting down...' }
|
216
220
|
@runner.try(:stop)
|
217
221
|
::Protobuf::Rpc::ServiceDirectory.instance.stop
|
218
|
-
|
222
|
+
logger.info { 'Shutdown complete' }
|
219
223
|
end
|
220
224
|
|
221
225
|
# Start the runner and log the relevant options.
|
@@ -223,7 +227,7 @@ module Protobuf
|
|
223
227
|
debug_say('Running server')
|
224
228
|
|
225
229
|
@runner.run do
|
226
|
-
|
230
|
+
logger.info {
|
227
231
|
"pid #{::Process.pid} -- #{@runner_mode} RPC Server listening at #{options.host}:#{options.port}"
|
228
232
|
}
|
229
233
|
|
@@ -67,8 +67,8 @@ module Protobuf
|
|
67
67
|
raise TypeError, "Unacceptable value #{val} for field #{field.name} of type #{field.type_class}"
|
68
68
|
end
|
69
69
|
rescue NoMethodError => ex
|
70
|
-
|
71
|
-
|
70
|
+
logger.error { ex.message }
|
71
|
+
logger.error { ex.backtrace.join("\n") }
|
72
72
|
raise TypeError, "Got NoMethodError attempting to set #{val} for field #{field.name} of type #{field.type_class}: #{ex.message}"
|
73
73
|
end
|
74
74
|
end
|
data/lib/protobuf/lifecycle.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Logging
|
3
|
+
def self.initialize_logger(log_target=$stdout, log_level=::Logger::INFO)
|
4
|
+
@counter ||= 0
|
5
|
+
@counter = @counter + 1
|
6
|
+
old_logger = defined?(@logger) ? @logger : nil
|
7
|
+
@logger = Logger.new(log_target)
|
8
|
+
@logger.level = log_level
|
9
|
+
old_logger.close if old_logger and close_old_logger?
|
10
|
+
@logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.close_old_logger=(boolean)
|
14
|
+
@close_old_logger = !!boolean
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.close_old_logger?
|
18
|
+
defined?(@close_old_logger) ? @close_old_logger : true
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.logger
|
22
|
+
defined?(@logger) ? @logger : initialize_logger
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.logger=(new_logger)
|
26
|
+
@logger = new_logger
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger
|
30
|
+
::Protobuf::Logging.logger
|
31
|
+
end
|
32
|
+
|
33
|
+
def log_exception(ex)
|
34
|
+
logger.error { ex.message }
|
35
|
+
logger.error { ex.backtrace[0..5].join("\n") }
|
36
|
+
logger.debug { ex.backtrace.join("\n") }
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_signature
|
40
|
+
@_log_signature ||= "[#{self.class == Class ? self.name : self.class.name}]"
|
41
|
+
end
|
42
|
+
|
43
|
+
def sign_message(message)
|
44
|
+
"#{log_signature} #{message}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Inspired by [mperham](https://github.com/mperham/sidekiq)
|
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/logging'
|
4
4
|
require 'protobuf/rpc/error'
|
5
5
|
require 'protobuf/rpc/connector'
|
6
6
|
|
@@ -8,7 +8,7 @@ module Protobuf
|
|
8
8
|
module Rpc
|
9
9
|
class Client
|
10
10
|
extend Forwardable
|
11
|
-
include Protobuf::
|
11
|
+
include Protobuf::Logging
|
12
12
|
|
13
13
|
def_delegators :@connector, :options, :complete_cb, :success_cb, :failure_cb
|
14
14
|
attr_reader :connector
|
@@ -29,7 +29,7 @@ module Protobuf
|
|
29
29
|
def initialize(options = {})
|
30
30
|
raise "Invalid client configuration. Service must be defined." if options[:service].nil?
|
31
31
|
@connector = Connector.connector_for_client.new(options)
|
32
|
-
|
32
|
+
logger.debug { sign_message("Initialized with options: #{options.inspect}") }
|
33
33
|
end
|
34
34
|
|
35
35
|
def log_signature
|
@@ -106,28 +106,28 @@ module Protobuf
|
|
106
106
|
def method_missing(method_name, *params)
|
107
107
|
service = options[:service]
|
108
108
|
unless service.rpc_method?(method_name)
|
109
|
-
|
109
|
+
logger.error { sign_message("#{service.name}##{method_name.to_s} not rpc method, passing to super") }
|
110
110
|
super(method_name, *params)
|
111
111
|
else
|
112
|
-
|
112
|
+
logger.debug { sign_message("#{service.name}##{method_name.to_s}") }
|
113
113
|
rpc = service.rpcs[method_name.to_sym]
|
114
114
|
|
115
115
|
options[:request_type] = rpc.request_type
|
116
|
-
|
116
|
+
logger.debug { sign_message("Request Type: #{options[:request_type].name}") }
|
117
117
|
|
118
118
|
options[:response_type] = rpc.response_type
|
119
|
-
|
119
|
+
logger.debug { sign_message("Response Type: #{options[:response_type].name}") }
|
120
120
|
|
121
121
|
options[:method] = method_name.to_s
|
122
122
|
options[:request] = params[0].is_a?(Hash) ? options[:request_type].new(params[0]) : params[0]
|
123
|
-
|
123
|
+
logger.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
|
-
|
127
|
+
logger.debug { sign_message("client setup callback given, invoking") }
|
128
128
|
yield(self)
|
129
129
|
else
|
130
|
-
|
130
|
+
logger.debug { sign_message("no block given for callbacks") }
|
131
131
|
end
|
132
132
|
|
133
133
|
send_request
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'timeout'
|
2
|
-
require 'protobuf/
|
2
|
+
require 'protobuf/logging'
|
3
3
|
require 'protobuf/rpc/rpc.pb'
|
4
4
|
require 'protobuf/rpc/buffer'
|
5
5
|
require 'protobuf/rpc/error'
|
@@ -23,7 +23,7 @@ module Protobuf
|
|
23
23
|
}
|
24
24
|
|
25
25
|
class Base
|
26
|
-
include Protobuf::
|
26
|
+
include Protobuf::Logging
|
27
27
|
|
28
28
|
attr_reader :options
|
29
29
|
attr_accessor :success_cb, :failure_cb, :complete_cb
|
@@ -19,17 +19,17 @@ module Protobuf
|
|
19
19
|
|
20
20
|
def complete
|
21
21
|
@stats.stop
|
22
|
-
|
23
|
-
|
22
|
+
logger.info { @stats.to_s }
|
23
|
+
logger.debug { sign_message('Response proceessing complete') }
|
24
24
|
@complete_cb.call(self) unless @complete_cb.nil?
|
25
25
|
rescue => e
|
26
|
-
|
26
|
+
logger.error { sign_message('Complete callback error encountered') }
|
27
27
|
log_exception(e)
|
28
28
|
raise
|
29
29
|
end
|
30
30
|
|
31
31
|
def data_callback(data)
|
32
|
-
|
32
|
+
logger.debug { sign_message('Using data_callback') }
|
33
33
|
@used_data_callback = true
|
34
34
|
@data = data
|
35
35
|
end
|
@@ -42,11 +42,11 @@ module Protobuf
|
|
42
42
|
@error = ClientError.new
|
43
43
|
@error.code = Protobuf::Socketrpc::ErrorReason.fetch(code)
|
44
44
|
@error.message = message
|
45
|
-
|
45
|
+
logger.debug { sign_message("Server failed request (invoking on_failure): #{@error.inspect}") }
|
46
46
|
|
47
47
|
@failure_cb.call(@error) unless @failure_cb.nil?
|
48
48
|
rescue => e
|
49
|
-
|
49
|
+
logger.error { sign_message("Failure callback error encountered") }
|
50
50
|
log_exception(e)
|
51
51
|
raise
|
52
52
|
ensure
|
@@ -71,7 +71,7 @@ module Protobuf
|
|
71
71
|
# Close up the connection as we no longer need it
|
72
72
|
close_connection
|
73
73
|
|
74
|
-
|
74
|
+
logger.debug { sign_message("Parsing response from server (connection closed)") }
|
75
75
|
|
76
76
|
# Parse out the raw response
|
77
77
|
@stats.response_size = @response_data.size unless @response_data.nil?
|
@@ -79,13 +79,13 @@ module Protobuf
|
|
79
79
|
|
80
80
|
# Determine success or failure based on parsed data
|
81
81
|
if response_wrapper.has_field?(:error_reason)
|
82
|
-
|
82
|
+
logger.debug { sign_message("Error response parsed") }
|
83
83
|
|
84
84
|
# fail the call if we already know the client is failed
|
85
85
|
# (don't try to parse out the response payload)
|
86
86
|
fail(response_wrapper.error_reason, response_wrapper.error)
|
87
87
|
else
|
88
|
-
|
88
|
+
logger.debug { sign_message("Successful response parsed") }
|
89
89
|
|
90
90
|
# Ensure client_response is an instance
|
91
91
|
parsed = @options[:response_type].decode(response_wrapper.response_proto.to_s)
|
@@ -125,10 +125,10 @@ module Protobuf
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def succeed(response)
|
128
|
-
|
128
|
+
logger.debug { sign_message("Server succeeded request (invoking on_success)") }
|
129
129
|
@success_cb.call(response) unless @success_cb.nil?
|
130
130
|
rescue => e
|
131
|
-
|
131
|
+
logger.error { sign_message("Success callback error encountered") }
|
132
132
|
log_exception(e)
|
133
133
|
fail(:RPC_ERROR, "An exception occurred while calling on_success: #{e.message}")
|
134
134
|
ensure
|
@@ -153,7 +153,7 @@ module Protobuf
|
|
153
153
|
|
154
154
|
def verify_callbacks
|
155
155
|
unless any_callbacks?
|
156
|
-
|
156
|
+
logger.debug { sign_message("No callbacks set, using data_callback") }
|
157
157
|
@success_cb = @failure_cb = self.method(:data_callback)
|
158
158
|
end
|
159
159
|
end
|
@@ -5,7 +5,7 @@ module Protobuf
|
|
5
5
|
module Connectors
|
6
6
|
class Socket < Base
|
7
7
|
include Protobuf::Rpc::Connectors::Common
|
8
|
-
include Protobuf::
|
8
|
+
include Protobuf::Logging
|
9
9
|
|
10
10
|
def send_request
|
11
11
|
timeout_wrap do
|
@@ -24,18 +24,18 @@ module Protobuf
|
|
24
24
|
|
25
25
|
def close_connection
|
26
26
|
@socket.close
|
27
|
-
|
27
|
+
logger.debug { sign_message('Connector closed') }
|
28
28
|
end
|
29
29
|
|
30
30
|
def connect_to_rpc_server
|
31
31
|
@socket = TCPSocket.new(options[:host], options[:port])
|
32
|
-
|
32
|
+
logger.debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
|
33
33
|
end
|
34
34
|
|
35
35
|
# Method to determine error state, must be used with Connector api
|
36
36
|
def error?
|
37
37
|
return true if @error
|
38
|
-
|
38
|
+
logger.debug { sign_message("Error state : #{@socket.closed?}") }
|
39
39
|
@socket.closed?
|
40
40
|
end
|
41
41
|
|
@@ -51,7 +51,7 @@ module Protobuf
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def read_response
|
54
|
-
|
54
|
+
logger.debug { sign_message("error? is #{error?}") }
|
55
55
|
return if error?
|
56
56
|
response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
|
57
57
|
response_buffer << read_data
|
@@ -65,7 +65,7 @@ module Protobuf
|
|
65
65
|
request_buffer.set_data(@request_data)
|
66
66
|
@socket.write(request_buffer.write)
|
67
67
|
@socket.flush
|
68
|
-
|
68
|
+
logger.debug { sign_message("write closed") }
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -12,7 +12,7 @@ module Protobuf
|
|
12
12
|
# Included Modules
|
13
13
|
#
|
14
14
|
include Protobuf::Rpc::Connectors::Common
|
15
|
-
include Protobuf::
|
15
|
+
include Protobuf::Logging
|
16
16
|
|
17
17
|
##
|
18
18
|
# Class Constants
|
@@ -71,9 +71,9 @@ module Protobuf
|
|
71
71
|
if socket # Make sure the context builds the socket
|
72
72
|
socket.setsockopt(::ZMQ::LINGER, 0)
|
73
73
|
|
74
|
-
|
74
|
+
logger.debug { sign_message("Establishing connection: #{server_uri}") }
|
75
75
|
zmq_error_check(socket.connect(server_uri), :socket_connect)
|
76
|
-
|
76
|
+
logger.debug { sign_message("Connection established to #{server_uri}") }
|
77
77
|
|
78
78
|
if first_alive_load_balance?
|
79
79
|
begin
|
@@ -123,6 +123,8 @@ module Protobuf
|
|
123
123
|
def host_alive?(host)
|
124
124
|
return true unless ping_port_enabled?
|
125
125
|
socket = TCPSocket.new(host, ping_port.to_i)
|
126
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
127
|
+
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [1,0].pack('ii'))
|
126
128
|
|
127
129
|
true
|
128
130
|
rescue
|
@@ -155,21 +157,21 @@ module Protobuf
|
|
155
157
|
poller = ::ZMQ::Poller.new
|
156
158
|
poller.register_readable(socket)
|
157
159
|
|
158
|
-
|
160
|
+
logger.debug { sign_message("Sending Request (attempt #{attempt}, #{socket})") }
|
159
161
|
zmq_error_check(socket.send_string(@request_data), :socket_send_string)
|
160
|
-
|
162
|
+
logger.debug { sign_message("Waiting #{timeout} seconds for response (attempt #{attempt}, #{socket})") }
|
161
163
|
|
162
164
|
if poller.poll(timeout * 1000) == 1
|
163
165
|
zmq_error_check(socket.recv_string(@response_data = ""), :socket_recv_string)
|
164
|
-
|
166
|
+
logger.debug { sign_message("Response received (attempt #{attempt}, #{socket})") }
|
165
167
|
else
|
166
|
-
|
168
|
+
logger.debug { sign_message("Timed out waiting for response (attempt #{attempt}, #{socket})") }
|
167
169
|
raise RequestTimeout
|
168
170
|
end
|
169
171
|
ensure
|
170
|
-
|
172
|
+
logger.debug { sign_message("Closing Socket") }
|
171
173
|
zmq_error_check(socket.close, :socket_close) if socket
|
172
|
-
|
174
|
+
logger.debug { sign_message("Socket closed") }
|
173
175
|
end
|
174
176
|
|
175
177
|
# The service we're attempting to connect to
|