protobuf 3.3.6 → 3.4.0
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.
- checksums.yaml +7 -0
- data/.rubocop.yml +48 -0
- data/.rubocop_todo.yml +79 -0
- data/.travis.yml +12 -4
- data/Rakefile +14 -11
- data/bin/protoc-gen-ruby +0 -1
- data/bin/rpc_server +1 -0
- data/install-protobuf.sh +8 -0
- data/lib/protobuf.rb +30 -24
- data/lib/protobuf/cli.rb +35 -35
- data/lib/protobuf/code_generator.rb +11 -8
- data/lib/protobuf/decoder.rb +4 -5
- data/lib/protobuf/deprecation.rb +20 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +2 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +2 -0
- data/lib/protobuf/encoder.rb +9 -4
- data/lib/protobuf/enum.rb +38 -54
- data/lib/protobuf/field.rb +2 -2
- data/lib/protobuf/field/base_field.rb +28 -32
- data/lib/protobuf/field/bool_field.rb +4 -4
- data/lib/protobuf/field/bytes_field.rb +5 -4
- data/lib/protobuf/field/double_field.rb +0 -1
- data/lib/protobuf/field/enum_field.rb +4 -7
- data/lib/protobuf/field/field_array.rb +3 -4
- data/lib/protobuf/field/fixed32_field.rb +1 -1
- data/lib/protobuf/field/fixed64_field.rb +0 -1
- data/lib/protobuf/field/float_field.rb +0 -1
- data/lib/protobuf/field/int32_field.rb +0 -1
- data/lib/protobuf/field/int64_field.rb +0 -1
- data/lib/protobuf/field/integer_field.rb +0 -1
- data/lib/protobuf/field/message_field.rb +2 -3
- data/lib/protobuf/field/sfixed32_field.rb +0 -1
- data/lib/protobuf/field/sfixed64_field.rb +0 -1
- data/lib/protobuf/field/signed_integer_field.rb +0 -1
- data/lib/protobuf/field/sint32_field.rb +0 -1
- data/lib/protobuf/field/sint64_field.rb +0 -1
- data/lib/protobuf/field/string_field.rb +0 -1
- data/lib/protobuf/field/uint32_field.rb +0 -1
- data/lib/protobuf/field/uint64_field.rb +0 -1
- data/lib/protobuf/field/varint_field.rb +0 -1
- data/lib/protobuf/generators/base.rb +1 -2
- data/lib/protobuf/generators/enum_generator.rb +1 -2
- data/lib/protobuf/generators/extension_generator.rb +1 -2
- data/lib/protobuf/generators/field_generator.rb +4 -5
- data/lib/protobuf/generators/file_generator.rb +22 -27
- data/lib/protobuf/generators/group_generator.rb +15 -16
- data/lib/protobuf/generators/message_generator.rb +13 -14
- data/lib/protobuf/generators/printable.rb +9 -10
- data/lib/protobuf/generators/service_generator.rb +1 -2
- data/lib/protobuf/lifecycle.rb +20 -33
- data/lib/protobuf/logging.rb +4 -6
- data/lib/protobuf/message.rb +22 -16
- data/lib/protobuf/message/fields.rb +14 -17
- data/lib/protobuf/message/serialization.rb +6 -5
- data/lib/protobuf/rpc/buffer.rb +10 -12
- data/lib/protobuf/rpc/client.rb +12 -12
- data/lib/protobuf/rpc/connectors/base.rb +4 -3
- data/lib/protobuf/rpc/connectors/common.rb +15 -17
- data/lib/protobuf/rpc/connectors/socket.rb +2 -2
- data/lib/protobuf/rpc/connectors/zmq.rb +118 -108
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +2 -0
- data/lib/protobuf/rpc/env.rb +12 -12
- data/lib/protobuf/rpc/error.rb +1 -1
- data/lib/protobuf/rpc/error/client_error.rb +4 -4
- data/lib/protobuf/rpc/error/server_error.rb +6 -6
- data/lib/protobuf/rpc/middleware/exception_handler.rb +1 -1
- data/lib/protobuf/rpc/middleware/logger.rb +3 -3
- data/lib/protobuf/rpc/middleware/request_decoder.rb +5 -5
- data/lib/protobuf/rpc/middleware/response_encoder.rb +3 -3
- data/lib/protobuf/rpc/rpc.pb.rb +2 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +75 -65
- data/lib/protobuf/rpc/servers/socket/worker.rb +2 -2
- data/lib/protobuf/rpc/servers/socket_runner.rb +12 -6
- data/lib/protobuf/rpc/servers/zmq/broker.rb +10 -6
- data/lib/protobuf/rpc/servers/zmq/server.rb +20 -26
- data/lib/protobuf/rpc/servers/zmq/util.rb +7 -7
- data/lib/protobuf/rpc/servers/zmq/worker.rb +5 -7
- data/lib/protobuf/rpc/servers/zmq_runner.rb +14 -3
- data/lib/protobuf/rpc/service.rb +15 -15
- data/lib/protobuf/rpc/service_directory.rb +7 -11
- data/lib/protobuf/rpc/service_dispatcher.rb +3 -3
- data/lib/protobuf/rpc/service_filters.rb +27 -28
- data/lib/protobuf/rpc/stat.rb +4 -7
- data/lib/protobuf/socket.rb +0 -1
- data/lib/protobuf/tasks/compile.rake +2 -2
- data/lib/protobuf/version.rb +1 -1
- data/protobuf.gemspec +20 -4
- data/spec/benchmark/tasks.rb +49 -23
- data/spec/bin/protoc-gen-ruby_spec.rb +11 -6
- data/spec/encoding/all_types_spec.rb +91 -77
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/socket_server_spec.rb +9 -10
- data/spec/functional/zmq_server_spec.rb +21 -19
- data/spec/lib/protobuf/cli_spec.rb +20 -20
- data/spec/lib/protobuf/code_generator_spec.rb +6 -6
- data/spec/lib/protobuf/enum_spec.rb +57 -31
- data/spec/lib/protobuf/field/float_field_spec.rb +2 -2
- data/spec/lib/protobuf/field/int32_field_spec.rb +1 -1
- data/spec/lib/protobuf/field/string_field_spec.rb +7 -8
- data/spec/lib/protobuf/field_spec.rb +3 -6
- data/spec/lib/protobuf/generators/base_spec.rb +6 -6
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +22 -17
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +8 -9
- data/spec/lib/protobuf/generators/field_generator_spec.rb +14 -11
- data/spec/lib/protobuf/generators/file_generator_spec.rb +7 -4
- data/spec/lib/protobuf/generators/service_generator_spec.rb +14 -11
- data/spec/lib/protobuf/lifecycle_spec.rb +9 -4
- data/spec/lib/protobuf/message_spec.rb +63 -35
- data/spec/lib/protobuf/optionable_spec.rb +3 -3
- data/spec/lib/protobuf/rpc/client_spec.rb +2 -2
- data/spec/lib/protobuf/rpc/connector_spec.rb +1 -1
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +26 -18
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +4 -4
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +11 -9
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +2 -2
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +7 -7
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +14 -14
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +5 -5
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +1 -1
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +9 -7
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +9 -9
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +2 -2
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +24 -23
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +4 -4
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +84 -51
- data/spec/lib/protobuf/rpc/service_spec.rb +15 -14
- data/spec/lib/protobuf/rpc/stat_spec.rb +1 -1
- data/spec/lib/protobuf_spec.rb +9 -9
- data/spec/spec_helper.rb +7 -19
- data/spec/support/server.rb +29 -59
- data/spec/support/test/defaults.pb.rb +2 -0
- data/spec/support/test/enum.pb.rb +2 -0
- data/spec/support/test/extended.pb.rb +2 -0
- data/spec/support/test/google_unittest_import.pb.rb +2 -0
- data/spec/support/test/google_unittest_import_public.pb.rb +2 -0
- data/spec/support/test/multi_field_extensions.pb.rb +2 -0
- data/spec/support/test/resource.pb.rb +2 -0
- data/spec/support/test/resource_service.rb +17 -20
- metadata +153 -112
- data/lib/protobuf/deprecator.rb +0 -42
data/lib/protobuf/rpc/buffer.rb
CHANGED
@@ -9,7 +9,7 @@ module Protobuf
|
|
9
9
|
# constantize this so we don't re-initialize the regex every time we need it
|
10
10
|
SIZE_REGEX = /^\d+-/
|
11
11
|
|
12
|
-
def initialize(mode
|
12
|
+
def initialize(mode = :read)
|
13
13
|
@flush = false
|
14
14
|
@data = ""
|
15
15
|
@size = 0
|
@@ -24,11 +24,11 @@ module Protobuf
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def write(force_mode=true)
|
28
|
-
if force_mode
|
29
|
-
mode = :write
|
30
|
-
elsif
|
31
|
-
|
27
|
+
def write(force_mode = true)
|
28
|
+
if force_mode && reading?
|
29
|
+
self.mode = :write
|
30
|
+
elsif !force_mode && reading?
|
31
|
+
fail 'You chose to write the buffer when in read mode'
|
32
32
|
end
|
33
33
|
|
34
34
|
@size = @data.length
|
@@ -43,7 +43,7 @@ module Protobuf
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
def set_data(data)
|
46
|
+
def set_data(data) # rubocop:disable Style/AccessorMethodName
|
47
47
|
@data = data.to_s
|
48
48
|
@size = @data.size
|
49
49
|
end
|
@@ -60,19 +60,17 @@ module Protobuf
|
|
60
60
|
@flush
|
61
61
|
end
|
62
62
|
|
63
|
-
def get_data_size
|
63
|
+
def get_data_size # rubocop:disable Style/AccessorMethodName
|
64
64
|
if @size == 0 || @data.match(SIZE_REGEX)
|
65
65
|
sliced_size = @data.slice!(SIZE_REGEX)
|
66
66
|
@size = sliced_size.gsub('-', '').to_i unless sliced_size.nil?
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
|
70
|
+
private
|
71
71
|
|
72
72
|
def check_for_flush
|
73
|
-
if !@size.nil? && @data.length == @size
|
74
|
-
@flush = true
|
75
|
-
end
|
73
|
+
@flush = true if !@size.nil? && @data.length == @size
|
76
74
|
end
|
77
75
|
end
|
78
76
|
end
|
data/lib/protobuf/rpc/client.rb
CHANGED
@@ -27,7 +27,7 @@ module Protobuf
|
|
27
27
|
# })
|
28
28
|
#
|
29
29
|
def initialize(options = {})
|
30
|
-
|
30
|
+
fail "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
|
@@ -46,8 +46,8 @@ module Protobuf
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def on_complete=(callable)
|
49
|
-
if callable
|
50
|
-
|
49
|
+
if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
|
50
|
+
fail "callable must take a single argument and respond to :call"
|
51
51
|
end
|
52
52
|
|
53
53
|
@connector.complete_cb = callable
|
@@ -65,8 +65,8 @@ module Protobuf
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def on_failure=(callable)
|
68
|
-
if callable
|
69
|
-
|
68
|
+
if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
|
69
|
+
fail "Callable must take a single argument and respond to :call"
|
70
70
|
end
|
71
71
|
|
72
72
|
@connector.failure_cb = callable
|
@@ -84,8 +84,8 @@ module Protobuf
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def on_success=(callable)
|
87
|
-
if callable
|
88
|
-
|
87
|
+
if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
|
88
|
+
fail "Callable must take a single argument and respond to :call"
|
89
89
|
end
|
90
90
|
|
91
91
|
@connector.success_cb = callable
|
@@ -105,11 +105,8 @@ module Protobuf
|
|
105
105
|
#
|
106
106
|
def method_missing(method_name, *params)
|
107
107
|
service = options[:service]
|
108
|
-
|
109
|
-
logger.
|
110
|
-
super(method_name, *params)
|
111
|
-
else
|
112
|
-
logger.debug { sign_message("#{service.name}##{method_name.to_s}") }
|
108
|
+
if service.rpc_method?(method_name)
|
109
|
+
logger.debug { sign_message("#{service.name}##{method_name}") }
|
113
110
|
rpc = service.rpcs[method_name.to_sym]
|
114
111
|
|
115
112
|
options[:request_type] = rpc.request_type
|
@@ -131,6 +128,9 @@ module Protobuf
|
|
131
128
|
end
|
132
129
|
|
133
130
|
send_request
|
131
|
+
else
|
132
|
+
logger.error { sign_message("#{service.name}##{method_name} not rpc method, passing to super") }
|
133
|
+
super(method_name, *params)
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
@@ -30,15 +30,16 @@ module Protobuf
|
|
30
30
|
|
31
31
|
def initialize(options)
|
32
32
|
@options = DEFAULT_OPTIONS.merge(options)
|
33
|
+
@stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
|
33
34
|
end
|
34
35
|
|
35
36
|
def first_alive_load_balance?
|
36
|
-
ENV.
|
37
|
+
ENV.key?("PB_FIRST_ALIVE_LOAD_BALANCE") ||
|
37
38
|
options[:first_alive_load_balance]
|
38
39
|
end
|
39
40
|
|
40
41
|
def send_request
|
41
|
-
|
42
|
+
fail 'If you inherit a Connector from Base you must implement send_request'
|
42
43
|
end
|
43
44
|
|
44
45
|
def ping_port
|
@@ -46,7 +47,7 @@ module Protobuf
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def ping_port_enabled?
|
49
|
-
ENV.
|
50
|
+
ENV.key?("PB_RPC_PING_PORT")
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
@@ -8,9 +8,7 @@ module Protobuf
|
|
8
8
|
attr_reader :error
|
9
9
|
|
10
10
|
def any_callbacks?
|
11
|
-
|
12
|
-
reduction = (reduction || !cb.nil?)
|
13
|
-
end
|
11
|
+
[@complete_cb, @failure_cb, @success_cb].any?
|
14
12
|
end
|
15
13
|
|
16
14
|
def request_caller
|
@@ -38,7 +36,7 @@ module Protobuf
|
|
38
36
|
#
|
39
37
|
# @param [Symbol] code The code we're using (see ::Protobuf::Socketrpc::ErrorReason)
|
40
38
|
# @param [String] message The error message
|
41
|
-
def
|
39
|
+
def failure(code, message)
|
42
40
|
@error = ClientError.new
|
43
41
|
@error.code = Protobuf::Socketrpc::ErrorReason.fetch(code)
|
44
42
|
@error.message = message
|
@@ -54,13 +52,13 @@ module Protobuf
|
|
54
52
|
end
|
55
53
|
|
56
54
|
def initialize_stats
|
57
|
-
@stats = Protobuf::Rpc::Stat.new(:CLIENT)
|
55
|
+
@stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
|
58
56
|
@stats.server = [@options[:port], @options[:host]]
|
59
57
|
@stats.service = @options[:service].name
|
60
58
|
@stats.method_name = @options[:method].to_s
|
61
59
|
rescue => ex
|
62
60
|
log_exception(ex)
|
63
|
-
|
61
|
+
failure(:RPC_ERROR, "Invalid stats configuration. #{ex.message}")
|
64
62
|
end
|
65
63
|
|
66
64
|
def log_signature
|
@@ -78,20 +76,20 @@ module Protobuf
|
|
78
76
|
response_wrapper = Protobuf::Socketrpc::Response.decode(@response_data)
|
79
77
|
|
80
78
|
# Determine success or failure based on parsed data
|
81
|
-
if response_wrapper.
|
79
|
+
if response_wrapper.field?(:error_reason)
|
82
80
|
logger.debug { sign_message("Error response parsed") }
|
83
81
|
|
84
82
|
# fail the call if we already know the client is failed
|
85
83
|
# (don't try to parse out the response payload)
|
86
|
-
|
84
|
+
failure(response_wrapper.error_reason, response_wrapper.error)
|
87
85
|
else
|
88
86
|
logger.debug { sign_message("Successful response parsed") }
|
89
87
|
|
90
88
|
# Ensure client_response is an instance
|
91
89
|
parsed = @options[:response_type].decode(response_wrapper.response_proto.to_s)
|
92
90
|
|
93
|
-
if parsed.nil?
|
94
|
-
|
91
|
+
if parsed.nil? && !response_wrapper.field?(:error_reason)
|
92
|
+
failure(:BAD_RESPONSE_PROTO, 'Unable to parse response from server')
|
95
93
|
else
|
96
94
|
verify_callbacks
|
97
95
|
succeed(parsed)
|
@@ -103,7 +101,7 @@ module Protobuf
|
|
103
101
|
def post_init
|
104
102
|
send_data unless error?
|
105
103
|
rescue => e
|
106
|
-
|
104
|
+
failure(:RPC_ERROR, "Connection error: #{e.message}")
|
107
105
|
end
|
108
106
|
|
109
107
|
def request_bytes
|
@@ -115,7 +113,7 @@ module Protobuf
|
|
115
113
|
|
116
114
|
return ::Protobuf::Socketrpc::Request.encode(fields)
|
117
115
|
rescue => e
|
118
|
-
|
116
|
+
failure(:INVALID_REQUEST_PROTO, "Could not set request proto: #{e.message}")
|
119
117
|
end
|
120
118
|
|
121
119
|
def setup_connection
|
@@ -130,7 +128,7 @@ module Protobuf
|
|
130
128
|
rescue => e
|
131
129
|
logger.error { sign_message("Success callback error encountered") }
|
132
130
|
log_exception(e)
|
133
|
-
|
131
|
+
failure(:RPC_ERROR, "An exception occurred while calling on_success: #{e.message}")
|
134
132
|
ensure
|
135
133
|
complete
|
136
134
|
end
|
@@ -148,28 +146,28 @@ module Protobuf
|
|
148
146
|
def timeout_wrap(&block)
|
149
147
|
::Timeout.timeout(timeout, &block)
|
150
148
|
rescue ::Timeout::Error
|
151
|
-
|
149
|
+
failure(:RPC_FAILED, "The server took longer than #{timeout} seconds to respond")
|
152
150
|
end
|
153
151
|
|
154
152
|
def validate_request_type!
|
155
153
|
unless @options[:request].class == @options[:request_type]
|
156
154
|
expected = @options[:request_type].name
|
157
155
|
actual = @options[:request].class.name
|
158
|
-
|
156
|
+
failure(:INVALID_REQUEST_PROTO, "Expected request type to be type of #{expected}, got #{actual} instead")
|
159
157
|
end
|
160
158
|
end
|
161
159
|
|
162
160
|
def verify_callbacks
|
163
161
|
unless any_callbacks?
|
164
162
|
logger.debug { sign_message("No callbacks set, using data_callback") }
|
165
|
-
@success_cb = @failure_cb =
|
163
|
+
@success_cb = @failure_cb = method(:data_callback)
|
166
164
|
end
|
167
165
|
end
|
168
166
|
|
169
167
|
def verify_options!
|
170
168
|
# Verify the options that are necessary and merge them in
|
171
169
|
[:service, :method, :host, :port].each do |opt|
|
172
|
-
|
170
|
+
failure(:RPC_ERROR, "Invalid client connection configuration. #{opt} must be a defined option.") if @options[opt].nil?
|
173
171
|
end
|
174
172
|
end
|
175
173
|
end
|
@@ -28,8 +28,8 @@ module Protobuf
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def connect_to_rpc_server
|
31
|
-
@socket
|
32
|
-
logger.debug { sign_message("Connection established #{options[:host]}:#{options[:port]}")
|
31
|
+
@socket ||= TCPSocket.new(options[:host], options[:port])
|
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
|
@@ -24,21 +24,24 @@ module Protobuf
|
|
24
24
|
##
|
25
25
|
# Class Methods
|
26
26
|
#
|
27
|
+
def self.ping_port_responses
|
28
|
+
@ping_port_responses ||= ::ThreadSafe::Cache.new
|
29
|
+
end
|
30
|
+
|
27
31
|
def self.zmq_context
|
28
|
-
@zmq_contexts ||= Hash.new
|
32
|
+
@zmq_contexts ||= Hash.new do |hash, key|
|
29
33
|
hash[key] = ZMQ::Context.new
|
30
|
-
|
34
|
+
end
|
31
35
|
|
32
36
|
@zmq_contexts[Process.pid]
|
33
37
|
end
|
34
38
|
|
35
|
-
def self.ping_port_responses
|
36
|
-
@ping_port_responses ||= ::ThreadSafe::Cache.new
|
37
|
-
end
|
38
|
-
|
39
39
|
##
|
40
40
|
# Instance methods
|
41
41
|
#
|
42
|
+
def log_signature
|
43
|
+
@_log_signature ||= "[client-#{self.class}]"
|
44
|
+
end
|
42
45
|
|
43
46
|
# Start the request/response cycle. We implement the Lazy Pirate
|
44
47
|
# req/reply reliability pattern as laid out in the ZMQ Guide, Chapter 4.
|
@@ -50,10 +53,6 @@ module Protobuf
|
|
50
53
|
send_request_with_lazy_pirate unless error?
|
51
54
|
end
|
52
55
|
|
53
|
-
def log_signature
|
54
|
-
@_log_signature ||= "[client-#{self.class}]"
|
55
|
-
end
|
56
|
-
|
57
56
|
private
|
58
57
|
|
59
58
|
##
|
@@ -75,34 +74,14 @@ module Protobuf
|
|
75
74
|
# service. The LINGER is set to 0 so we can close immediately in
|
76
75
|
# the event of a timeout
|
77
76
|
def create_socket
|
78
|
-
socket =
|
77
|
+
socket = zmq_context.socket(::ZMQ::REQ)
|
79
78
|
|
80
79
|
begin
|
81
|
-
server_uri = lookup_server_uri
|
82
|
-
socket = zmq_context.socket(::ZMQ::REQ)
|
83
|
-
|
84
80
|
if socket # Make sure the context builds the socket
|
81
|
+
server_uri = lookup_server_uri
|
85
82
|
socket.setsockopt(::ZMQ::LINGER, 0)
|
86
83
|
zmq_error_check(socket.connect(server_uri), :socket_connect)
|
87
|
-
|
88
|
-
if first_alive_load_balance?
|
89
|
-
begin
|
90
|
-
check_available_response = ""
|
91
|
-
socket.setsockopt(::ZMQ::RCVTIMEO, check_available_rcv_timeout)
|
92
|
-
socket.setsockopt(::ZMQ::SNDTIMEO, check_available_snd_timeout)
|
93
|
-
zmq_recoverable_error_check(socket.send_string(::Protobuf::Rpc::Zmq::CHECK_AVAILABLE_MESSAGE), :socket_send_string)
|
94
|
-
zmq_recoverable_error_check(socket.recv_string(check_available_response), :socket_recv_string)
|
95
|
-
|
96
|
-
if check_available_response == ::Protobuf::Rpc::Zmq::NO_WORKERS_AVAILABLE
|
97
|
-
zmq_recoverable_error_check(socket.close, :socket_close)
|
98
|
-
end
|
99
|
-
rescue ZmqRecoverableError
|
100
|
-
socket = nil # couldn't make a connection and need to try again
|
101
|
-
else
|
102
|
-
socket.setsockopt(::ZMQ::RCVTIMEO, -1)
|
103
|
-
socket.setsockopt(::ZMQ::SNDTIMEO, -1)
|
104
|
-
end
|
105
|
-
end
|
84
|
+
socket = socket_to_available_server(socket) if first_alive_load_balance?
|
106
85
|
end
|
107
86
|
end while socket.try(:socket).nil?
|
108
87
|
|
@@ -115,28 +94,6 @@ module Protobuf
|
|
115
94
|
!! @error
|
116
95
|
end
|
117
96
|
|
118
|
-
# Lookup a server uri for the requested service in the service
|
119
|
-
# directory. If the service directory is not running, default
|
120
|
-
# to the host and port in the options
|
121
|
-
#
|
122
|
-
def lookup_server_uri
|
123
|
-
server_lookup_attempts.times do
|
124
|
-
service_directory.all_listings_for(service).each do |listing|
|
125
|
-
host = listing.try(:address)
|
126
|
-
port = listing.try(:port)
|
127
|
-
return "tcp://#{host}:#{port}" if host_alive?(host)
|
128
|
-
end
|
129
|
-
|
130
|
-
host = options[:host]
|
131
|
-
port = options[:port]
|
132
|
-
return "tcp://#{host}:#{port}" if host_alive?(host)
|
133
|
-
|
134
|
-
sleep (1.0/100.0)
|
135
|
-
end
|
136
|
-
|
137
|
-
raise "Host not found for service #{service}"
|
138
|
-
end
|
139
|
-
|
140
97
|
def host_alive?(host)
|
141
98
|
return true unless ping_port_enabled?
|
142
99
|
|
@@ -149,7 +106,7 @@ module Protobuf
|
|
149
106
|
ping_port_open = ping_port_open?(host)
|
150
107
|
self.class.ping_port_responses[host] = {
|
151
108
|
:at => Time.now.to_i,
|
152
|
-
:ping_port_open => ping_port_open
|
109
|
+
:ping_port_open => ping_port_open,
|
153
110
|
}
|
154
111
|
ping_port_open
|
155
112
|
end
|
@@ -158,32 +115,50 @@ module Protobuf
|
|
158
115
|
@host_alive_check_interval ||= [ENV["PB_ZMQ_CLIENT_HOST_ALIVE_CHECK_INTERVAL"].to_i, 1].max
|
159
116
|
end
|
160
117
|
|
118
|
+
# Lookup a server uri for the requested service in the service
|
119
|
+
# directory. If the service directory is not running, default
|
120
|
+
# to the host and port in the options
|
121
|
+
#
|
122
|
+
def lookup_server_uri
|
123
|
+
server_lookup_attempts.times do
|
124
|
+
first_alive_listing = service_directory.all_listings_for(service).find do |listing|
|
125
|
+
host_alive?(listing.try(:address))
|
126
|
+
end
|
127
|
+
|
128
|
+
if first_alive_listing
|
129
|
+
host = first_alive_listing.try(:address)
|
130
|
+
port = first_alive_listing.try(:port)
|
131
|
+
@stats.server = [port, host]
|
132
|
+
return "tcp://#{host}:#{port}"
|
133
|
+
end
|
134
|
+
|
135
|
+
host = options[:host]
|
136
|
+
port = options[:port]
|
137
|
+
|
138
|
+
if host_alive?(host)
|
139
|
+
@stats.server = [port, host]
|
140
|
+
return "tcp://#{host}:#{port}"
|
141
|
+
end
|
142
|
+
|
143
|
+
sleep(1.0 / 100.0)
|
144
|
+
end
|
145
|
+
|
146
|
+
fail "Host not found for service #{service}"
|
147
|
+
end
|
148
|
+
|
161
149
|
def ping_port_open?(host)
|
162
150
|
socket = TCPSocket.new(host, ping_port.to_i)
|
163
151
|
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
164
|
-
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [1,0].pack('ii'))
|
152
|
+
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [1, 0].pack('ii'))
|
165
153
|
|
166
154
|
true
|
167
155
|
rescue
|
168
156
|
false
|
169
157
|
ensure
|
170
|
-
socket.close rescue nil
|
171
|
-
end
|
172
|
-
|
173
|
-
# Trying a number of times, attempt to get a response from the server.
|
174
|
-
# If we haven't received a legitimate response in the CLIENT_RETRIES number
|
175
|
-
# of retries, fail the request.
|
176
|
-
#
|
177
|
-
def send_request_with_lazy_pirate
|
178
|
-
attempt = 0
|
179
|
-
|
180
158
|
begin
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
rescue RequestTimeout
|
185
|
-
retry if attempt < CLIENT_RETRIES
|
186
|
-
fail(:RPC_FAILED, "The server repeatedly failed to respond within #{timeout} seconds")
|
159
|
+
socket && socket.close
|
160
|
+
rescue IOError
|
161
|
+
nil
|
187
162
|
end
|
188
163
|
end
|
189
164
|
|
@@ -192,7 +167,7 @@ module Protobuf
|
|
192
167
|
case
|
193
168
|
when options[:timeout] then
|
194
169
|
options[:timeout]
|
195
|
-
when ENV.
|
170
|
+
when ENV.key?("PB_ZMQ_CLIENT_RCV_TIMEOUT") then
|
196
171
|
ENV["PB_ZMQ_CLIENT_RCV_TIMEOUT"].to_i
|
197
172
|
else
|
198
173
|
300_000 # 300 seconds
|
@@ -200,16 +175,20 @@ module Protobuf
|
|
200
175
|
end
|
201
176
|
end
|
202
177
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
178
|
+
# Trying a number of times, attempt to get a response from the server.
|
179
|
+
# If we haven't received a legitimate response in the CLIENT_RETRIES number
|
180
|
+
# of retries, fail the request.
|
181
|
+
#
|
182
|
+
def send_request_with_lazy_pirate
|
183
|
+
attempt = 0
|
184
|
+
|
185
|
+
begin
|
186
|
+
attempt += 1
|
187
|
+
send_request_with_timeout(attempt)
|
188
|
+
parse_response
|
189
|
+
rescue RequestTimeout
|
190
|
+
retry if attempt < CLIENT_RETRIES
|
191
|
+
failure(:RPC_FAILED, "The server repeatedly failed to respond within #{timeout} seconds")
|
213
192
|
end
|
214
193
|
end
|
215
194
|
|
@@ -247,6 +226,37 @@ module Protobuf
|
|
247
226
|
::Protobuf::Rpc::ServiceDirectory.instance
|
248
227
|
end
|
249
228
|
|
229
|
+
def snd_timeout
|
230
|
+
@snd_timeout ||= begin
|
231
|
+
case
|
232
|
+
when options[:timeout] then
|
233
|
+
options[:timeout]
|
234
|
+
when ENV.key?("PB_ZMQ_CLIENT_SND_TIMEOUT") then
|
235
|
+
ENV["PB_ZMQ_CLIENT_SND_TIMEOUT"].to_i
|
236
|
+
else
|
237
|
+
300_000 # 300 seconds
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def socket_to_available_server(socket)
|
243
|
+
check_available_response = ""
|
244
|
+
socket.setsockopt(::ZMQ::RCVTIMEO, check_available_rcv_timeout)
|
245
|
+
socket.setsockopt(::ZMQ::SNDTIMEO, check_available_snd_timeout)
|
246
|
+
zmq_recoverable_error_check(socket.send_string(::Protobuf::Rpc::Zmq::CHECK_AVAILABLE_MESSAGE), :socket_send_string)
|
247
|
+
zmq_recoverable_error_check(socket.recv_string(check_available_response), :socket_recv_string)
|
248
|
+
|
249
|
+
if check_available_response == ::Protobuf::Rpc::Zmq::NO_WORKERS_AVAILABLE
|
250
|
+
zmq_recoverable_error_check(socket.close, :socket_close)
|
251
|
+
end
|
252
|
+
|
253
|
+
socket.setsockopt(::ZMQ::RCVTIMEO, -1)
|
254
|
+
socket.setsockopt(::ZMQ::SNDTIMEO, -1)
|
255
|
+
socket
|
256
|
+
rescue ZmqRecoverableError
|
257
|
+
return nil # couldn't make a connection and need to try again
|
258
|
+
end
|
259
|
+
|
250
260
|
# Return the ZMQ Context to use for this process.
|
251
261
|
# If the context does not exist, create it, then register
|
252
262
|
# an exit block to ensure the context is terminated correctly.
|
@@ -256,41 +266,41 @@ module Protobuf
|
|
256
266
|
end
|
257
267
|
|
258
268
|
def zmq_eagain_error_check(return_code, source)
|
259
|
-
|
260
|
-
if ::ZMQ::Util.errno == ::ZMQ::EAGAIN
|
261
|
-
raise ZmqEagainError, <<-ERROR
|
262
|
-
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
269
|
+
return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
|
263
270
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
raise <<-ERROR
|
268
|
-
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
271
|
+
if ::ZMQ::Util.errno == ::ZMQ::EAGAIN
|
272
|
+
fail ZmqEagainError, <<-ERROR
|
273
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
269
274
|
|
270
|
-
|
271
|
-
|
272
|
-
|
275
|
+
#{caller(1).join($INPUT_RECORD_SEPARATOR)}
|
276
|
+
ERROR
|
277
|
+
else
|
278
|
+
fail <<-ERROR
|
279
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
280
|
+
|
281
|
+
#{caller(1).join($INPUT_RECORD_SEPARATOR)}
|
282
|
+
ERROR
|
273
283
|
end
|
274
284
|
end
|
275
285
|
|
276
286
|
def zmq_error_check(return_code, source)
|
277
|
-
|
278
|
-
raise <<-ERROR
|
279
|
-
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
287
|
+
return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
|
280
288
|
|
281
|
-
|
282
|
-
|
283
|
-
|
289
|
+
fail <<-ERROR
|
290
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
291
|
+
|
292
|
+
#{caller(1).join($INPUT_RECORD_SEPARATOR)}
|
293
|
+
ERROR
|
284
294
|
end
|
285
295
|
|
286
296
|
def zmq_recoverable_error_check(return_code, source)
|
287
|
-
|
288
|
-
raise ZmqRecoverableError, <<-ERROR
|
289
|
-
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
297
|
+
return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
|
290
298
|
|
291
|
-
|
292
|
-
|
293
|
-
|
299
|
+
fail ZmqRecoverableError, <<-ERROR
|
300
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
301
|
+
|
302
|
+
#{caller(1).join($INPUT_RECORD_SEPARATOR)}
|
303
|
+
ERROR
|
294
304
|
end
|
295
305
|
end
|
296
306
|
end
|