protobuf 2.7.12 → 2.8.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/README.md +39 -2
  2. data/lib/protobuf.rb +17 -26
  3. data/lib/protobuf/cli.rb +106 -86
  4. data/lib/protobuf/field/bytes_field.rb +6 -8
  5. data/lib/protobuf/field/float_field.rb +5 -1
  6. data/lib/protobuf/field/string_field.rb +7 -8
  7. data/lib/protobuf/rpc/connectors/base.rb +1 -1
  8. data/lib/protobuf/rpc/connectors/zmq.rb +157 -29
  9. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +49 -0
  10. data/lib/protobuf/rpc/error/client_error.rb +5 -5
  11. data/lib/protobuf/rpc/error/server_error.rb +7 -7
  12. data/lib/protobuf/rpc/rpc.pb.rb +13 -12
  13. data/lib/protobuf/rpc/servers/evented_runner.rb +11 -6
  14. data/lib/protobuf/rpc/servers/socket/server.rb +19 -15
  15. data/lib/protobuf/rpc/servers/socket_runner.rb +21 -18
  16. data/lib/protobuf/rpc/servers/zmq/broker.rb +104 -94
  17. data/lib/protobuf/rpc/servers/zmq/server.rb +263 -43
  18. data/lib/protobuf/rpc/servers/zmq/util.rb +18 -6
  19. data/lib/protobuf/rpc/servers/zmq/worker.rb +102 -39
  20. data/lib/protobuf/rpc/servers/zmq_runner.rb +31 -20
  21. data/lib/protobuf/rpc/service.rb +24 -12
  22. data/lib/protobuf/rpc/service_directory.rb +206 -0
  23. data/lib/protobuf/rpc/stat.rb +1 -1
  24. data/lib/protobuf/version.rb +1 -1
  25. data/proto/dynamic_discovery.proto +44 -0
  26. data/spec/benchmark/tasks.rb +1 -3
  27. data/spec/functional/socket_server_spec.rb +6 -5
  28. data/spec/functional/zmq_server_spec.rb +59 -30
  29. data/spec/lib/protobuf/cli_spec.rb +49 -54
  30. data/spec/lib/protobuf/enum_spec.rb +1 -1
  31. data/spec/lib/protobuf/rpc/client_spec.rb +1 -1
  32. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +43 -1
  33. data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +2 -1
  34. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +9 -8
  35. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +24 -19
  36. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +5 -5
  37. data/spec/lib/protobuf/rpc/service_directory_spec.rb +183 -0
  38. data/spec/support/server.rb +21 -12
  39. data/spec/support/test/resource.pb.rb +6 -0
  40. data/spec/support/test/resource.proto +5 -0
  41. data/spec/support/test/resource_service.rb +7 -0
  42. metadata +70 -38
  43. checksums.yaml +0 -7
  44. data/spec/lib/protobuf/field/string_field_spec.rb +0 -46
  45. data/spec/lib/protobuf/rpc/servers/zmq/broker_spec.rb +0 -31
@@ -4,6 +4,10 @@ module Protobuf
4
4
  module Field
5
5
  class FloatField < BaseField
6
6
  def self.default; 0.0; end
7
+ def self.max; 1.0/0; end
8
+ def self.min; -1.0/0; end
9
+ def max; 1.0/0; end
10
+ def min; -1.0/0; end
7
11
 
8
12
  def wire_type
9
13
  WireType::FIXED32
@@ -18,7 +22,7 @@ module Protobuf
18
22
  end
19
23
 
20
24
  def acceptable?(val)
21
- val.respond_to?(:to_f)
25
+ (val > min || val < max) rescue false
22
26
  end
23
27
  end
24
28
  end
@@ -6,18 +6,17 @@ module Protobuf
6
6
  ENCODING = 'UTF-8'.freeze
7
7
 
8
8
  def decode(bytes)
9
- bytes_to_decode = bytes.dup
10
- bytes_to_decode.force_encoding(::Protobuf::Field::StringField::ENCODING)
11
- bytes_to_decode
9
+ bytes.force_encoding(::Protobuf::Field::StringField::ENCODING)
10
+ bytes
12
11
  end
13
12
 
14
13
  def encode(value)
15
- value_to_encode = value.dup
16
- value_to_encode.encode!(::Protobuf::Field::StringField::ENCODING, :invalid => :replace, :undef => :replace, :replace => "")
17
- value_to_encode.force_encoding(::Protobuf::Field::BytesField::BYTES_ENCODING)
14
+ # TODO: make replace character configurable?
15
+ value.encode!(::Protobuf::Field::StringField::ENCODING, :invalid => :replace, :undef => :replace, :replace => "")
16
+ value.force_encoding(::Protobuf::Field::BytesField::BYTES_ENCODING)
18
17
 
19
- string_size = ::Protobuf::Field::VarintField.encode(value_to_encode.size)
20
- string_size << value_to_encode
18
+ string_size = ::Protobuf::Field::VarintField.encode(value.size)
19
+ string_size << value
21
20
  end
22
21
  end
23
22
  end
@@ -17,7 +17,7 @@ module Protobuf
17
17
  :request => nil, # The request object sent by the client
18
18
  :request_type => nil, # The request type expected by the client
19
19
  :response_type => nil, # The response type expected by the client
20
- :timeout => 300, # The default timeout for the request, also handled by client.rb
20
+ :timeout => 15, # The default timeout for the request, also handled by client.rb
21
21
  :client_host => nil # The hostname or address of this client
22
22
  }
23
23
 
@@ -1,23 +1,38 @@
1
1
  require 'protobuf/rpc/connectors/base'
2
+ require 'protobuf/rpc/service_directory'
2
3
 
3
4
  module Protobuf
4
5
  module Rpc
5
6
  module Connectors
6
7
  class Zmq < Base
8
+
9
+ ##
10
+ # Included Modules
11
+ #
12
+
7
13
  include Protobuf::Rpc::Connectors::Common
8
14
  include Protobuf::Logger::LogMethods
9
15
 
16
+ ##
17
+ # Class Constants
18
+ #
19
+
20
+ CLIENT_RETRIES = (ENV['PB_CLIENT_RETRIES'] || 3)
21
+
22
+ ##
23
+ # Instance methods
24
+ #
25
+
26
+ # Start the request/response cycle. We implement the Lazy Pirate
27
+ # req/reply reliability pattern as laid out in the ZMQ Guide, Chapter 4.
28
+ #
29
+ # @see http://zguide.zeromq.org/php:chapter4#Client-side-Reliability-Lazy-Pirate-Pattern
30
+ #
10
31
  def send_request
11
- timeout_wrap do
12
- setup_connection
13
- connect_to_rpc_server
14
- post_init
15
- read_response
16
- end
32
+ setup_connection
33
+ poll_send_data
17
34
  ensure
18
- @socket.close if @socket
19
- @zmq_context.terminate if @zmq_context
20
- @zmq_context = nil
35
+ close_connection
21
36
  end
22
37
 
23
38
  def log_signature
@@ -26,45 +41,158 @@ module Protobuf
26
41
 
27
42
  private
28
43
 
44
+ ##
45
+ # Private Instance methods
46
+ #
47
+
29
48
  def close_connection
30
- return if @error
31
- zmq_error_check(@socket.close)
32
- zmq_error_check(@zmq_context.terminate)
33
- log_debug { sign_message("Connector closed") }
49
+ socket_close
50
+ zmq_context_terminate
34
51
  end
35
52
 
53
+ # Establish a request socket connection to the remote rpc_server.
54
+ # Set the socket option LINGER to 0 so that we don't wait
55
+ # for queued messages to be accepted when the socket/context are
56
+ # asked to close/terminate.
57
+ #
36
58
  def connect_to_rpc_server
37
- return if @error
38
- log_debug { sign_message("Establishing connection: #{options[:host]}:#{options[:port]}") }
39
- @zmq_context = ::ZMQ::Context.new
40
- @socket = @zmq_context.socket(::ZMQ::REQ)
41
- zmq_error_check(@socket.connect("tcp://#{options[:host]}:#{options[:port]}"))
42
- log_debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
59
+ return if error?
60
+
61
+ server_uri = lookup_server_uri
62
+ log_debug { sign_message("Establishing connection: #{server_uri}") }
63
+ socket.setsockopt(::ZMQ::LINGER, 0)
64
+ zmq_error_check(socket.connect(server_uri), :socket_connect)
65
+ zmq_error_check(poller.register_readable(socket), :poller_register_readable)
66
+ log_debug { sign_message("Connection established to #{server_uri}") }
43
67
  end
44
68
 
45
- # Method to determine error state, must be used with Connector api
69
+ # Method to determine error state, must be used with Connector API.
70
+ #
46
71
  def error?
47
- !!@error
72
+ !! @error
73
+ end
74
+
75
+ # Lookup a server uri for the requested service in the service
76
+ # directory. If the service directory is not running, default
77
+ # to the host and port in the options
78
+ #
79
+ def lookup_server_uri
80
+ if service_directory.running?
81
+ listing = service_directory.lookup(service)
82
+ host, port = listing.address, listing.port if listing
83
+ end
84
+
85
+ host, port = options[:host], options[:port] unless host && port
86
+
87
+ "tcp://#{host}:#{port}"
88
+ end
89
+
90
+ # Trying a number of times, attempt to get a response from the server.
91
+ # If we haven't received a legitimate response in the CLIENT_RETRIES number
92
+ # of retries, fail the request.
93
+ #
94
+ def poll_send_data
95
+ return if error?
96
+
97
+ poll_timeout = (options[:timeout].to_f / CLIENT_RETRIES.to_f) * 1000
98
+
99
+ CLIENT_RETRIES.times do |n|
100
+ connect_to_rpc_server
101
+ log_debug { sign_message("Sending Request (attempt #{n + 1}, #{socket})") }
102
+ send_data
103
+ log_debug { sign_message("Request sending complete (attempt #{n + 1}, #{socket})") }
104
+
105
+ if poller.poll(poll_timeout) == 1
106
+ read_response
107
+ return
108
+ else
109
+ close_connection
110
+ end
111
+ end
112
+
113
+ fail(:RPC_FAILED, "The server took longer than #{options[:timeout]} seconds to respond")
48
114
  end
49
115
 
116
+ def poller
117
+ @poller ||= ::ZMQ::Poller.new
118
+ end
119
+
120
+ # Read the string response from the available readable. This will be
121
+ # the current @socket. Calls `parse_response` to invoke the success or
122
+ # failed callbacks, depending on the state of the communication
123
+ # and response data.
124
+ #
50
125
  def read_response
51
- return if @error
126
+ return if error?
127
+
52
128
  @response_data = ''
53
- zmq_error_check(@socket.recv_string(@response_data))
129
+ zmq_error_check(socket.recv_string(@response_data), :socket_recv_string)
130
+
54
131
  parse_response
55
132
  end
56
133
 
134
+ # Send the request data to the remote rpc_server.
135
+ #
57
136
  def send_data
58
- return if @error
59
- log_debug { sign_message("Sending Request: #{@request_data}") }
137
+ return if error?
138
+
60
139
  @stats.request_size = @request_data.size
61
- zmq_error_check(@socket.send_string(@request_data))
62
- log_debug { sign_message("write closed") }
140
+ zmq_error_check(socket.send_string(@request_data), :socket_send_string)
141
+ end
142
+
143
+ # The service we're attempting to connect to
144
+ #
145
+ def service
146
+ options[:service]
147
+ end
148
+
149
+ # Alias for ::Protobuf::Rpc::ServiceDirectory.instance
150
+ def service_directory
151
+ ::Protobuf::Rpc::ServiceDirectory.instance
152
+ end
153
+
154
+ # Setup a ZMQ request socket in the current zmq context.
155
+ #
156
+ def socket
157
+ @socket ||= zmq_context.socket(::ZMQ::REQ)
63
158
  end
64
159
 
65
- def zmq_error_check(return_code)
66
- raise "Last API call failed at #{caller(1)}" unless return_code >= 0
160
+ def socket_close
161
+ if socket
162
+ log_debug { sign_message("Closing Socket") }
163
+ zmq_error_check(socket.close, :socket_close)
164
+ log_debug { sign_message("Socket closed") }
165
+ @socket = nil
166
+ end
167
+ end
168
+
169
+ # Return the ZMQ Context to use for this process.
170
+ # If the context does not exist, create it, then register
171
+ # an exit block to ensure the context is terminated correctly.
172
+ #
173
+ def zmq_context
174
+ @zmq_context ||= ::ZMQ::Context.new
175
+ end
176
+
177
+ # Terminate the zmq_context (if any).
178
+ #
179
+ def zmq_context_terminate
180
+ log_debug { sign_message("Terminating ZMQ Context") }
181
+ @zmq_context.try(:terminate)
182
+ @zmq_context = nil
183
+ log_debug { sign_message("ZMQ Context terminated") }
67
184
  end
185
+
186
+ def zmq_error_check(return_code, source)
187
+ unless ::ZMQ::Util.resultcode_ok?(return_code || -1)
188
+ raise <<-ERROR
189
+ Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
190
+
191
+ #{caller(1).join($/)}
192
+ ERROR
193
+ end
194
+ end
195
+
68
196
  end
69
197
  end
70
198
  end
@@ -0,0 +1,49 @@
1
+ ##
2
+ # This file is auto-generated. DO NOT EDIT!
3
+ #
4
+ require 'protobuf/message'
5
+
6
+ module Protobuf
7
+
8
+ module Rpc
9
+
10
+ module DynamicDiscovery
11
+
12
+ ##
13
+ # Enum Classes
14
+ #
15
+ class BeaconType < ::Protobuf::Enum
16
+ define :HEARTBEAT, 0
17
+ define :FLATLINE, 1
18
+ end
19
+
20
+
21
+ ##
22
+ # Message Classes
23
+ #
24
+ class Server < ::Protobuf::Message; end
25
+ class Beacon < ::Protobuf::Message; end
26
+
27
+ ##
28
+ # Message Fields
29
+ #
30
+ class Server
31
+ optional ::Protobuf::Field::StringField, :uuid, 1
32
+ optional ::Protobuf::Field::StringField, :address, 2
33
+ optional ::Protobuf::Field::StringField, :port, 3
34
+ optional ::Protobuf::Field::Int32Field, :ttl, 4
35
+ repeated ::Protobuf::Field::StringField, :services, 5
36
+ end
37
+
38
+ class Beacon
39
+ optional ::Protobuf::Rpc::DynamicDiscovery::BeaconType, :beacon_type, 1
40
+ optional ::Protobuf::Rpc::DynamicDiscovery::Server, :server, 2
41
+ end
42
+
43
+
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
@@ -2,30 +2,30 @@ require 'protobuf/rpc/error'
2
2
 
3
3
  module Protobuf
4
4
  module Rpc
5
-
5
+
6
6
  class InvalidRequestProto < PbError
7
7
  def initialize(message='Invalid request type given')
8
8
  super message, 'INVALID_REQUEST_PROTO'
9
9
  end
10
10
  end
11
-
11
+
12
12
  class BadResponseProto < PbError
13
13
  def initialize(message='Bad response type from server')
14
14
  super message, 'BAD_RESPONSE_PROTO'
15
15
  end
16
16
  end
17
-
17
+
18
18
  class UnkownHost < PbError
19
19
  def initialize(message='Unknown host or port')
20
20
  super message, 'UNKNOWN_HOST'
21
21
  end
22
22
  end
23
-
23
+
24
24
  class IOError < PbError
25
25
  def initialize(message='IO Error occurred')
26
26
  super message, 'IO_ERROR'
27
27
  end
28
28
  end
29
-
29
+
30
30
  end
31
31
  end
@@ -2,42 +2,42 @@ require 'protobuf/rpc/rpc.pb'
2
2
 
3
3
  module Protobuf
4
4
  module Rpc
5
-
5
+
6
6
  class BadRequestData < PbError
7
7
  def initialize message='Unable to parse request'
8
8
  super message, 'BAD_REQUEST_DATA'
9
9
  end
10
10
  end
11
-
11
+
12
12
  class BadRequestProto < PbError
13
13
  def initialize message='Request is of wrong type'
14
14
  super message, 'BAD_REQUEST_PROTO'
15
15
  end
16
16
  end
17
-
17
+
18
18
  class ServiceNotFound < PbError
19
19
  def initialize message='Service class not found'
20
20
  super message, 'SERVICE_NOT_FOUND'
21
21
  end
22
22
  end
23
-
23
+
24
24
  class MethodNotFound < PbError
25
25
  def initialize message='Service method not found'
26
26
  super message, 'METHOD_NOT_FOUND'
27
27
  end
28
28
  end
29
-
29
+
30
30
  class RpcError < PbError
31
31
  def initialize message='RPC exception occurred'
32
32
  super message, 'RPC_ERROR'
33
33
  end
34
34
  end
35
-
35
+
36
36
  class RpcFailed < PbError
37
37
  def initialize message='RPC failed'
38
38
  super message, 'RPC_FAILED'
39
39
  end
40
40
  end
41
-
41
+
42
42
  end
43
43
  end
@@ -4,22 +4,13 @@
4
4
  require 'protobuf/message'
5
5
 
6
6
  module Protobuf
7
+
7
8
  module Socketrpc
9
+
8
10
  ##
9
11
  # Enum Classes
10
12
  #
11
- class ErrorReason < ::Protobuf::Enum; end
12
-
13
- ##
14
- # Message Classes
15
- #
16
- class Request < ::Protobuf::Message; end
17
- class Response < ::Protobuf::Message; end
18
-
19
- ##
20
- # Enum Values
21
- #
22
- class ErrorReason
13
+ class ErrorReason < ::Protobuf::Enum
23
14
  define :BAD_REQUEST_DATA, 0
24
15
  define :BAD_REQUEST_PROTO, 1
25
16
  define :SERVICE_NOT_FOUND, 2
@@ -32,6 +23,13 @@ module Protobuf
32
23
  define :IO_ERROR, 9
33
24
  end
34
25
 
26
+
27
+ ##
28
+ # Message Classes
29
+ #
30
+ class Request < ::Protobuf::Message; end
31
+ class Response < ::Protobuf::Message; end
32
+
35
33
  ##
36
34
  # Message Fields
37
35
  #
@@ -49,5 +47,8 @@ module Protobuf
49
47
  optional ::Protobuf::Socketrpc::ErrorReason, :error_reason, 4
50
48
  end
51
49
 
50
+
52
51
  end
52
+
53
53
  end
54
+