protobuf 2.7.11-java → 2.8.0.beta1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) 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/float_field.rb +5 -1
  5. data/lib/protobuf/rpc/connectors/base.rb +1 -1
  6. data/lib/protobuf/rpc/connectors/zmq.rb +157 -29
  7. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +49 -0
  8. data/lib/protobuf/rpc/error/client_error.rb +5 -5
  9. data/lib/protobuf/rpc/error/server_error.rb +7 -7
  10. data/lib/protobuf/rpc/rpc.pb.rb +13 -12
  11. data/lib/protobuf/rpc/servers/evented_runner.rb +11 -6
  12. data/lib/protobuf/rpc/servers/socket/server.rb +19 -15
  13. data/lib/protobuf/rpc/servers/socket_runner.rb +21 -18
  14. data/lib/protobuf/rpc/servers/zmq/broker.rb +104 -94
  15. data/lib/protobuf/rpc/servers/zmq/server.rb +263 -43
  16. data/lib/protobuf/rpc/servers/zmq/util.rb +18 -6
  17. data/lib/protobuf/rpc/servers/zmq/worker.rb +102 -39
  18. data/lib/protobuf/rpc/servers/zmq_runner.rb +31 -20
  19. data/lib/protobuf/rpc/service.rb +24 -12
  20. data/lib/protobuf/rpc/service_directory.rb +206 -0
  21. data/lib/protobuf/rpc/stat.rb +1 -1
  22. data/lib/protobuf/version.rb +1 -1
  23. data/proto/dynamic_discovery.proto +44 -0
  24. data/spec/benchmark/tasks.rb +1 -3
  25. data/spec/functional/socket_server_spec.rb +6 -5
  26. data/spec/functional/zmq_server_spec.rb +59 -30
  27. data/spec/lib/protobuf/cli_spec.rb +49 -54
  28. data/spec/lib/protobuf/enum_spec.rb +1 -1
  29. data/spec/lib/protobuf/rpc/client_spec.rb +1 -1
  30. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +43 -1
  31. data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +2 -1
  32. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +9 -8
  33. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +24 -19
  34. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +5 -5
  35. data/spec/lib/protobuf/rpc/service_directory_spec.rb +183 -0
  36. data/spec/support/server.rb +21 -12
  37. data/spec/support/test/resource.pb.rb +6 -0
  38. data/spec/support/test/resource.proto +5 -0
  39. data/spec/support/test/resource_service.rb +7 -0
  40. metadata +11 -11
  41. data/spec/lib/protobuf/rpc/servers/zmq/broker_spec.rb +0 -31
@@ -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
+
@@ -2,22 +2,27 @@ module Protobuf
2
2
  module Rpc
3
3
  class EventedRunner
4
4
 
5
- def self.register_signals
6
- # Noop
5
+ def initialize(options)
6
+ @options = options
7
7
  end
8
8
 
9
- def self.run(options)
9
+ def run
10
10
  # Startup and run the rpc server
11
11
  ::EventMachine.schedule do
12
- ::EventMachine.start_server(options[:host], options[:port], ::Protobuf::Rpc::Evented::Server)
12
+ ::EventMachine.start_server(
13
+ @options[:host],
14
+ @options[:port],
15
+ ::Protobuf::Rpc::Evented::Server
16
+ )
13
17
  end
14
18
 
15
19
  # Join or start the reactor
16
- yield if block_given?
20
+ yield if block_given?
21
+
17
22
  ::EM.reactor_running? ? ::EM.reactor_thread.join : ::EM.run
18
23
  end
19
24
 
20
- def self.stop
25
+ def stop
21
26
  ::EventMachine.stop_event_loop if ::EventMachine.reactor_running?
22
27
  end
23
28
 
@@ -11,12 +11,16 @@ module Protobuf
11
11
 
12
12
  AUTO_COLLECT_TIMEOUT = 5 # seconds
13
13
 
14
- def self.cleanup?
14
+ def initialize(options)
15
+ @options = options
16
+ end
17
+
18
+ def cleanup?
15
19
  # every 10 connections run a cleanup routine after closing the response
16
20
  @threads.size > (@threshold - 1) && (@threads.size % @threshold) == 0
17
21
  end
18
22
 
19
- def self.cleanup_threads
23
+ def cleanup_threads
20
24
  log_debug { sign_message("Thread cleanup - #{@threads.size} - start") }
21
25
 
22
26
  @threads = @threads.select do |t|
@@ -32,11 +36,11 @@ module Protobuf
32
36
  log_debug { sign_message("Thread cleanup - #{@threads.size} - complete") }
33
37
  end
34
38
 
35
- def self.log_signature
39
+ def log_signature
36
40
  @_log_signature ||= "server-#{self.class.name}"
37
41
  end
38
42
 
39
- def self.new_worker(socket)
43
+ def new_worker(socket)
40
44
  Thread.new(socket) do |sock|
41
45
  ::Protobuf::Rpc::Socket::Worker.new(sock) do |s|
42
46
  s.close
@@ -44,12 +48,12 @@ module Protobuf
44
48
  end
45
49
  end
46
50
 
47
- def self.run(options = {})
51
+ def run
48
52
  log_debug { sign_message("Run") }
49
- host = options[:host]
50
- port = options[:port]
51
- backlog = options[:backlog]
52
- @threshold = options[:threshold]
53
+ host = @options[:host]
54
+ port = @options[:port]
55
+ backlog = @options[:backlog]
56
+ @threshold = @options[:threshold]
53
57
 
54
58
  @threads = []
55
59
  @server = ::TCPServer.new(host, port)
@@ -62,8 +66,9 @@ module Protobuf
62
66
 
63
67
  while running?
64
68
  log_debug { sign_message("Waiting for connections") }
69
+ ready_cnxns = IO.select(@listen_fds, [], [], AUTO_COLLECT_TIMEOUT) rescue nil
65
70
 
66
- if ready_cnxns = IO.select(@listen_fds, [], [], AUTO_COLLECT_TIMEOUT)
71
+ if ready_cnxns
67
72
  cnxns = ready_cnxns.first
68
73
  cnxns.each do |client|
69
74
  case
@@ -96,16 +101,15 @@ module Protobuf
96
101
  raise #if running?
97
102
  end
98
103
 
99
- def self.running?
100
- @running
104
+ def running?
105
+ !!@running
101
106
  end
102
107
 
103
- def self.stop
108
+ def stop
104
109
  @running = false
105
- @server.close if @server
110
+ @server.try(:close)
106
111
  end
107
112
  end
108
-
109
113
  end
110
114
  end
111
115
  end