protobuf 2.7.11-java → 2.8.0.beta1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +39 -2
- data/lib/protobuf.rb +17 -26
- data/lib/protobuf/cli.rb +106 -86
- data/lib/protobuf/field/float_field.rb +5 -1
- data/lib/protobuf/rpc/connectors/base.rb +1 -1
- data/lib/protobuf/rpc/connectors/zmq.rb +157 -29
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +49 -0
- data/lib/protobuf/rpc/error/client_error.rb +5 -5
- data/lib/protobuf/rpc/error/server_error.rb +7 -7
- data/lib/protobuf/rpc/rpc.pb.rb +13 -12
- data/lib/protobuf/rpc/servers/evented_runner.rb +11 -6
- data/lib/protobuf/rpc/servers/socket/server.rb +19 -15
- data/lib/protobuf/rpc/servers/socket_runner.rb +21 -18
- data/lib/protobuf/rpc/servers/zmq/broker.rb +104 -94
- data/lib/protobuf/rpc/servers/zmq/server.rb +263 -43
- data/lib/protobuf/rpc/servers/zmq/util.rb +18 -6
- data/lib/protobuf/rpc/servers/zmq/worker.rb +102 -39
- data/lib/protobuf/rpc/servers/zmq_runner.rb +31 -20
- data/lib/protobuf/rpc/service.rb +24 -12
- data/lib/protobuf/rpc/service_directory.rb +206 -0
- data/lib/protobuf/rpc/stat.rb +1 -1
- data/lib/protobuf/version.rb +1 -1
- data/proto/dynamic_discovery.proto +44 -0
- data/spec/benchmark/tasks.rb +1 -3
- data/spec/functional/socket_server_spec.rb +6 -5
- data/spec/functional/zmq_server_spec.rb +59 -30
- data/spec/lib/protobuf/cli_spec.rb +49 -54
- data/spec/lib/protobuf/enum_spec.rb +1 -1
- data/spec/lib/protobuf/rpc/client_spec.rb +1 -1
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +43 -1
- data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +2 -1
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +9 -8
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +24 -19
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +5 -5
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +183 -0
- data/spec/support/server.rb +21 -12
- data/spec/support/test/resource.pb.rb +6 -0
- data/spec/support/test/resource.proto +5 -0
- data/spec/support/test/resource_service.rb +7 -0
- metadata +11 -11
- 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
|
-
|
12
|
-
|
13
|
-
connect_to_rpc_server
|
14
|
-
post_init
|
15
|
-
read_response
|
16
|
-
end
|
32
|
+
setup_connection
|
33
|
+
poll_send_data
|
17
34
|
ensure
|
18
|
-
|
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
|
-
|
31
|
-
|
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
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
69
|
+
# Method to determine error state, must be used with Connector API.
|
70
|
+
#
|
46
71
|
def error?
|
47
|
-
|
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
|
126
|
+
return if error?
|
127
|
+
|
52
128
|
@response_data = ''
|
53
|
-
zmq_error_check(
|
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
|
59
|
-
|
137
|
+
return if error?
|
138
|
+
|
60
139
|
@stats.request_size = @request_data.size
|
61
|
-
zmq_error_check(
|
62
|
-
|
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
|
66
|
-
|
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
|
data/lib/protobuf/rpc/rpc.pb.rb
CHANGED
@@ -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
|
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
|
6
|
-
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
9
|
+
def run
|
10
10
|
# Startup and run the rpc server
|
11
11
|
::EventMachine.schedule do
|
12
|
-
::EventMachine.start_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
|
-
|
20
|
+
yield if block_given?
|
21
|
+
|
17
22
|
::EM.reactor_running? ? ::EM.reactor_thread.join : ::EM.run
|
18
23
|
end
|
19
24
|
|
20
|
-
def
|
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
|
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
|
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
|
39
|
+
def log_signature
|
36
40
|
@_log_signature ||= "server-#{self.class.name}"
|
37
41
|
end
|
38
42
|
|
39
|
-
def
|
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
|
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
|
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
|
100
|
-
|
104
|
+
def running?
|
105
|
+
!!@running
|
101
106
|
end
|
102
107
|
|
103
|
-
def
|
108
|
+
def stop
|
104
109
|
@running = false
|
105
|
-
@server.close
|
110
|
+
@server.try(:close)
|
106
111
|
end
|
107
112
|
end
|
108
|
-
|
109
113
|
end
|
110
114
|
end
|
111
115
|
end
|