protobuf-cucumber 3.10.4
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/.gitignore +21 -0
- data/.rubocop.yml +70 -0
- data/.rubocop_todo.yml +145 -0
- data/.travis.yml +40 -0
- data/.yardopts +5 -0
- data/CHANGES.md +344 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +64 -0
- data/bin/protoc-gen-ruby +22 -0
- data/bin/rpc_server +5 -0
- data/install-protobuf.sh +28 -0
- data/lib/protobuf.rb +129 -0
- data/lib/protobuf/cli.rb +257 -0
- data/lib/protobuf/code_generator.rb +120 -0
- data/lib/protobuf/decoder.rb +28 -0
- data/lib/protobuf/deprecation.rb +117 -0
- data/lib/protobuf/descriptors.rb +3 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +62 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +301 -0
- data/lib/protobuf/encoder.rb +11 -0
- data/lib/protobuf/enum.rb +365 -0
- data/lib/protobuf/exceptions.rb +9 -0
- data/lib/protobuf/field.rb +74 -0
- data/lib/protobuf/field/base_field.rb +380 -0
- data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
- data/lib/protobuf/field/bool_field.rb +64 -0
- data/lib/protobuf/field/bytes_field.rb +78 -0
- data/lib/protobuf/field/double_field.rb +25 -0
- data/lib/protobuf/field/enum_field.rb +61 -0
- data/lib/protobuf/field/field_array.rb +104 -0
- data/lib/protobuf/field/field_hash.rb +122 -0
- data/lib/protobuf/field/fixed32_field.rb +25 -0
- data/lib/protobuf/field/fixed64_field.rb +28 -0
- data/lib/protobuf/field/float_field.rb +43 -0
- data/lib/protobuf/field/int32_field.rb +21 -0
- data/lib/protobuf/field/int64_field.rb +34 -0
- data/lib/protobuf/field/integer_field.rb +23 -0
- data/lib/protobuf/field/message_field.rb +51 -0
- data/lib/protobuf/field/sfixed32_field.rb +27 -0
- data/lib/protobuf/field/sfixed64_field.rb +28 -0
- data/lib/protobuf/field/signed_integer_field.rb +29 -0
- data/lib/protobuf/field/sint32_field.rb +21 -0
- data/lib/protobuf/field/sint64_field.rb +21 -0
- data/lib/protobuf/field/string_field.rb +51 -0
- data/lib/protobuf/field/uint32_field.rb +21 -0
- data/lib/protobuf/field/uint64_field.rb +21 -0
- data/lib/protobuf/field/varint_field.rb +77 -0
- data/lib/protobuf/generators/base.rb +85 -0
- data/lib/protobuf/generators/enum_generator.rb +39 -0
- data/lib/protobuf/generators/extension_generator.rb +27 -0
- data/lib/protobuf/generators/field_generator.rb +193 -0
- data/lib/protobuf/generators/file_generator.rb +262 -0
- data/lib/protobuf/generators/group_generator.rb +122 -0
- data/lib/protobuf/generators/message_generator.rb +104 -0
- data/lib/protobuf/generators/option_generator.rb +17 -0
- data/lib/protobuf/generators/printable.rb +160 -0
- data/lib/protobuf/generators/service_generator.rb +50 -0
- data/lib/protobuf/lifecycle.rb +33 -0
- data/lib/protobuf/logging.rb +39 -0
- data/lib/protobuf/message.rb +260 -0
- data/lib/protobuf/message/fields.rb +233 -0
- data/lib/protobuf/message/serialization.rb +85 -0
- data/lib/protobuf/optionable.rb +70 -0
- data/lib/protobuf/rpc/buffer.rb +78 -0
- data/lib/protobuf/rpc/client.rb +140 -0
- data/lib/protobuf/rpc/connectors/base.rb +221 -0
- data/lib/protobuf/rpc/connectors/ping.rb +89 -0
- data/lib/protobuf/rpc/connectors/socket.rb +78 -0
- data/lib/protobuf/rpc/connectors/zmq.rb +319 -0
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +50 -0
- data/lib/protobuf/rpc/env.rb +60 -0
- data/lib/protobuf/rpc/error.rb +28 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/middleware.rb +25 -0
- data/lib/protobuf/rpc/middleware/exception_handler.rb +40 -0
- data/lib/protobuf/rpc/middleware/logger.rb +95 -0
- data/lib/protobuf/rpc/middleware/request_decoder.rb +79 -0
- data/lib/protobuf/rpc/middleware/response_encoder.rb +83 -0
- data/lib/protobuf/rpc/middleware/runner.rb +18 -0
- data/lib/protobuf/rpc/rpc.pb.rb +64 -0
- data/lib/protobuf/rpc/rpc_method.rb +16 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +121 -0
- data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
- data/lib/protobuf/rpc/servers/socket_runner.rb +46 -0
- data/lib/protobuf/rpc/servers/zmq/broker.rb +194 -0
- data/lib/protobuf/rpc/servers/zmq/server.rb +321 -0
- data/lib/protobuf/rpc/servers/zmq/util.rb +48 -0
- data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
- data/lib/protobuf/rpc/servers/zmq_runner.rb +70 -0
- data/lib/protobuf/rpc/service.rb +172 -0
- data/lib/protobuf/rpc/service_directory.rb +261 -0
- data/lib/protobuf/rpc/service_dispatcher.rb +45 -0
- data/lib/protobuf/rpc/service_filters.rb +250 -0
- data/lib/protobuf/rpc/stat.rb +119 -0
- data/lib/protobuf/socket.rb +21 -0
- data/lib/protobuf/tasks.rb +1 -0
- data/lib/protobuf/tasks/compile.rake +80 -0
- data/lib/protobuf/varint.rb +20 -0
- data/lib/protobuf/varint_pure.rb +31 -0
- data/lib/protobuf/version.rb +3 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf/zmq.rb +21 -0
- data/profile.html +5103 -0
- data/proto/dynamic_discovery.proto +44 -0
- data/proto/google/protobuf/compiler/plugin.proto +147 -0
- data/proto/google/protobuf/descriptor.proto +779 -0
- data/proto/rpc.proto +69 -0
- data/protobuf-cucumber.gemspec +57 -0
- data/spec/benchmark/tasks.rb +143 -0
- data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
- data/spec/encoding/all_types_spec.rb +103 -0
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/class_inheritance_spec.rb +52 -0
- data/spec/functional/code_generator_spec.rb +58 -0
- data/spec/functional/socket_server_spec.rb +59 -0
- data/spec/functional/zmq_server_spec.rb +105 -0
- data/spec/lib/protobuf/cli_spec.rb +317 -0
- data/spec/lib/protobuf/code_generator_spec.rb +87 -0
- data/spec/lib/protobuf/enum_spec.rb +307 -0
- data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
- data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/enum_field_spec.rb +44 -0
- data/spec/lib/protobuf/field/field_array_spec.rb +105 -0
- data/spec/lib/protobuf/field/field_hash_spec.rb +168 -0
- data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +120 -0
- data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
- data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +79 -0
- data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field_spec.rb +192 -0
- data/spec/lib/protobuf/generators/base_spec.rb +154 -0
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +82 -0
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +42 -0
- data/spec/lib/protobuf/generators/field_generator_spec.rb +197 -0
- data/spec/lib/protobuf/generators/file_generator_spec.rb +119 -0
- data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
- data/spec/lib/protobuf/generators/service_generator_spec.rb +99 -0
- data/spec/lib/protobuf/lifecycle_spec.rb +94 -0
- data/spec/lib/protobuf/message_spec.rb +944 -0
- data/spec/lib/protobuf/optionable_spec.rb +265 -0
- data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +226 -0
- data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +34 -0
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +110 -0
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +91 -0
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +43 -0
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +293 -0
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +517 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +162 -0
- data/spec/lib/protobuf/rpc/stat_spec.rb +101 -0
- data/spec/lib/protobuf/varint_spec.rb +29 -0
- data/spec/lib/protobuf_spec.rb +105 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/all.rb +6 -0
- data/spec/support/packed_field.rb +23 -0
- data/spec/support/protos/all_types.data.bin +0 -0
- data/spec/support/protos/all_types.data.txt +119 -0
- data/spec/support/protos/enum.pb.rb +63 -0
- data/spec/support/protos/enum.proto +37 -0
- data/spec/support/protos/extreme_values.data.bin +0 -0
- data/spec/support/protos/google_unittest.bin +0 -0
- data/spec/support/protos/google_unittest.pb.rb +798 -0
- data/spec/support/protos/google_unittest.proto +884 -0
- data/spec/support/protos/google_unittest_custom_options.bin +0 -0
- data/spec/support/protos/google_unittest_custom_options.pb.rb +361 -0
- data/spec/support/protos/google_unittest_custom_options.proto +424 -0
- data/spec/support/protos/google_unittest_import.pb.rb +55 -0
- data/spec/support/protos/google_unittest_import.proto +73 -0
- data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
- data/spec/support/protos/google_unittest_import_public.proto +41 -0
- data/spec/support/protos/map-test.bin +157 -0
- data/spec/support/protos/map-test.pb.rb +85 -0
- data/spec/support/protos/map-test.proto +68 -0
- data/spec/support/protos/multi_field_extensions.pb.rb +59 -0
- data/spec/support/protos/multi_field_extensions.proto +35 -0
- data/spec/support/protos/resource.pb.rb +172 -0
- data/spec/support/protos/resource.proto +137 -0
- data/spec/support/resource_service.rb +23 -0
- data/spec/support/server.rb +65 -0
- data/spec/support/test_app_file.rb +2 -0
- data/varint_prof.rb +82 -0
- metadata +579 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Rpc
|
5
|
+
module Connectors
|
6
|
+
class Ping
|
7
|
+
attr_reader :host, :port
|
8
|
+
|
9
|
+
def initialize(host, port)
|
10
|
+
@host = host
|
11
|
+
@port = port
|
12
|
+
end
|
13
|
+
|
14
|
+
def online?
|
15
|
+
socket = tcp_socket
|
16
|
+
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [1, 0].pack('ii'))
|
17
|
+
|
18
|
+
true
|
19
|
+
rescue
|
20
|
+
false
|
21
|
+
ensure
|
22
|
+
begin
|
23
|
+
socket && socket.close
|
24
|
+
rescue IOError
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def timeout
|
30
|
+
@timeout ||= begin
|
31
|
+
if ::ENV.key?("PB_RPC_PING_PORT_TIMEOUT")
|
32
|
+
::ENV["PB_RPC_PING_PORT_TIMEOUT"].to_f / 1000
|
33
|
+
else
|
34
|
+
0.2 # 200 ms
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def tcp_socket
|
42
|
+
# Reference: http://stackoverflow.com/a/21014439/1457934
|
43
|
+
socket = ::Socket.new(family, ::Socket::SOCK_STREAM, 0)
|
44
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
45
|
+
socket.connect_nonblock(sockaddr)
|
46
|
+
socket
|
47
|
+
rescue ::IO::WaitWritable
|
48
|
+
# IO.select will block until the socket is writable or the timeout
|
49
|
+
# is exceeded - whichever comes first.
|
50
|
+
if ::IO.select(nil, [socket], nil, timeout)
|
51
|
+
begin
|
52
|
+
# Verify there is now a good connection
|
53
|
+
socket.connect_nonblock(sockaddr)
|
54
|
+
socket
|
55
|
+
rescue ::Errno::EISCONN
|
56
|
+
# Socket is connected.
|
57
|
+
socket
|
58
|
+
rescue
|
59
|
+
# An unexpected exception was raised - the connection is no good.
|
60
|
+
socket.close
|
61
|
+
raise
|
62
|
+
end
|
63
|
+
else
|
64
|
+
# IO.select returns nil when the socket is not ready before timeout
|
65
|
+
# seconds have elapsed
|
66
|
+
socket.close
|
67
|
+
raise "Connection Timeout"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def family
|
72
|
+
@family ||= ::Socket.const_get(addrinfo[0][0])
|
73
|
+
end
|
74
|
+
|
75
|
+
def addrinfo
|
76
|
+
@addrinfo ||= ::Socket.getaddrinfo(host, nil)
|
77
|
+
end
|
78
|
+
|
79
|
+
def ip
|
80
|
+
@ip ||= addrinfo[0][3]
|
81
|
+
end
|
82
|
+
|
83
|
+
def sockaddr
|
84
|
+
@sockaddr ||= ::Socket.pack_sockaddr_in(port, ip)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'protobuf/rpc/connectors/base'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Rpc
|
5
|
+
module Connectors
|
6
|
+
class Socket < Base
|
7
|
+
include Protobuf::Logging
|
8
|
+
|
9
|
+
def send_request
|
10
|
+
timeout_wrap do
|
11
|
+
setup_connection
|
12
|
+
connect_to_rpc_server
|
13
|
+
post_init
|
14
|
+
read_response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def log_signature
|
19
|
+
@_log_signature ||= "[client-#{self.class}]"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def close_connection
|
25
|
+
@socket.close
|
26
|
+
logger.debug { sign_message('Connector closed') }
|
27
|
+
end
|
28
|
+
|
29
|
+
def connect_to_rpc_server
|
30
|
+
@socket ||= TCPSocket.new(options[:host], options[:port])
|
31
|
+
logger.debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Method to determine error state, must be used with Connector api
|
35
|
+
def error?
|
36
|
+
return true if @error
|
37
|
+
logger.debug { sign_message("Error state : #{@socket.closed?}") }
|
38
|
+
@socket.closed?
|
39
|
+
end
|
40
|
+
|
41
|
+
def post_init
|
42
|
+
send_data unless error?
|
43
|
+
rescue => e
|
44
|
+
failure(:RPC_ERROR, "Connection error: #{e.message}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_data
|
48
|
+
size_io = StringIO.new
|
49
|
+
|
50
|
+
until (size_reader = @socket.getc) == "-"
|
51
|
+
size_io << size_reader
|
52
|
+
end
|
53
|
+
str_size_io = size_io.string
|
54
|
+
|
55
|
+
"#{str_size_io}-#{@socket.read(str_size_io.to_i)}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_response
|
59
|
+
logger.debug { sign_message("error? is #{error?}") }
|
60
|
+
return if error?
|
61
|
+
response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
|
62
|
+
response_buffer << read_data
|
63
|
+
@response_data = response_buffer.data
|
64
|
+
parse_response if response_buffer.flushed?
|
65
|
+
end
|
66
|
+
|
67
|
+
def send_data
|
68
|
+
return if error?
|
69
|
+
request_buffer = ::Protobuf::Rpc::Buffer.new(:write)
|
70
|
+
request_buffer.set_data(@request_data)
|
71
|
+
@socket.write(request_buffer.write)
|
72
|
+
@socket.flush
|
73
|
+
logger.debug { sign_message("write closed") }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
require "thread_safe"
|
2
|
+
require "protobuf/rpc/connectors/base"
|
3
|
+
require "protobuf/rpc/connectors/ping"
|
4
|
+
require "protobuf/rpc/service_directory"
|
5
|
+
|
6
|
+
module Protobuf
|
7
|
+
module Rpc
|
8
|
+
module Connectors
|
9
|
+
class Zmq < Base
|
10
|
+
RequestTimeout = Class.new(RuntimeError)
|
11
|
+
ZmqRecoverableError = Class.new(RuntimeError)
|
12
|
+
ZmqEagainError = Class.new(RuntimeError)
|
13
|
+
|
14
|
+
##
|
15
|
+
# Included Modules
|
16
|
+
#
|
17
|
+
include Protobuf::Logging
|
18
|
+
|
19
|
+
##
|
20
|
+
# Class Constants
|
21
|
+
#
|
22
|
+
CLIENT_RETRIES = (ENV['PB_CLIENT_RETRIES'] || 3)
|
23
|
+
|
24
|
+
##
|
25
|
+
# Class Methods
|
26
|
+
#
|
27
|
+
def self.ping_port_responses
|
28
|
+
@ping_port_responses ||= ::ThreadSafe::Cache.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.zmq_context(reload = false)
|
32
|
+
@zmq_contexts = nil if reload
|
33
|
+
@zmq_contexts ||= Hash.new do |hash, key|
|
34
|
+
hash[key] = ZMQ::Context.new
|
35
|
+
end
|
36
|
+
|
37
|
+
@zmq_contexts[Process.pid]
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Instance methods
|
42
|
+
#
|
43
|
+
def log_signature
|
44
|
+
@_log_signature ||= "[client-#{self.class}]"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Start the request/response cycle. We implement the Lazy Pirate
|
48
|
+
# req/reply reliability pattern as laid out in the ZMQ Guide, Chapter 4.
|
49
|
+
#
|
50
|
+
# @see http://zguide.zeromq.org/php:chapter4#Client-side-Reliability-Lazy-Pirate-Pattern
|
51
|
+
#
|
52
|
+
def send_request
|
53
|
+
setup_connection
|
54
|
+
send_request_with_lazy_pirate unless error?
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
##
|
60
|
+
# Private Instance methods
|
61
|
+
#
|
62
|
+
def check_available_rcv_timeout
|
63
|
+
@check_available_rcv_timeout ||= begin
|
64
|
+
case
|
65
|
+
when ENV.key?("PB_ZMQ_CLIENT_CHECK_AVAILABLE_RCV_TIMEOUT") then
|
66
|
+
ENV["PB_ZMQ_CLIENT_CHECK_AVAILABLE_RCV_TIMEOUT"].to_i
|
67
|
+
else
|
68
|
+
200 # ms
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def check_available_snd_timeout
|
74
|
+
@check_available_snd_timeout ||= begin
|
75
|
+
case
|
76
|
+
when ENV.key?("PB_ZMQ_CLIENT_CHECK_AVAILABLE_SND_TIMEOUT") then
|
77
|
+
ENV["PB_ZMQ_CLIENT_CHECK_AVAILABLE_SND_TIMEOUT"].to_i
|
78
|
+
else
|
79
|
+
200 # ms
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def close_connection
|
85
|
+
# The socket is automatically closed after every request.
|
86
|
+
end
|
87
|
+
|
88
|
+
# Create a socket connected to a server that can handle the current
|
89
|
+
# service. The LINGER is set to 0 so we can close immediately in
|
90
|
+
# the event of a timeout
|
91
|
+
def create_socket
|
92
|
+
attempt_number = 0
|
93
|
+
|
94
|
+
begin
|
95
|
+
attempt_number += 1
|
96
|
+
socket = zmq_context.socket(::ZMQ::REQ)
|
97
|
+
|
98
|
+
if socket # Make sure the context builds the socket
|
99
|
+
server_uri = lookup_server_uri
|
100
|
+
socket.setsockopt(::ZMQ::LINGER, 0)
|
101
|
+
zmq_error_check(socket.connect(server_uri), :socket_connect)
|
102
|
+
socket = socket_to_available_server(socket) if first_alive_load_balance?
|
103
|
+
end
|
104
|
+
end while socket.try(:socket).nil? && attempt_number < socket_creation_attempts
|
105
|
+
|
106
|
+
raise RequestTimeout, "Cannot create new ZMQ client socket" if socket.try(:socket).nil?
|
107
|
+
socket
|
108
|
+
end
|
109
|
+
|
110
|
+
# Method to determine error state, must be used with Connector API.
|
111
|
+
#
|
112
|
+
def error?
|
113
|
+
!! @error
|
114
|
+
end
|
115
|
+
|
116
|
+
def host_alive?(host)
|
117
|
+
return true unless ping_port_enabled?
|
118
|
+
|
119
|
+
if (last_response = self.class.ping_port_responses[host])
|
120
|
+
if (Time.now.to_i - last_response[:at]) <= host_alive_check_interval
|
121
|
+
return last_response[:ping_port_open]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
ping_port_open = ping_port_open?(host)
|
126
|
+
self.class.ping_port_responses[host] = {
|
127
|
+
:at => Time.now.to_i,
|
128
|
+
:ping_port_open => ping_port_open,
|
129
|
+
}
|
130
|
+
ping_port_open
|
131
|
+
end
|
132
|
+
|
133
|
+
def host_alive_check_interval
|
134
|
+
@host_alive_check_interval ||= [ENV["PB_ZMQ_CLIENT_HOST_ALIVE_CHECK_INTERVAL"].to_i, 1].max
|
135
|
+
end
|
136
|
+
|
137
|
+
# Lookup a server uri for the requested service in the service
|
138
|
+
# directory. If the service directory is not running, default
|
139
|
+
# to the host and port in the options
|
140
|
+
#
|
141
|
+
def lookup_server_uri
|
142
|
+
server_lookup_attempts.times do
|
143
|
+
first_alive_listing = service_directory.all_listings_for(service).find do |listing|
|
144
|
+
host_alive?(listing.try(:address))
|
145
|
+
end
|
146
|
+
|
147
|
+
if first_alive_listing
|
148
|
+
host = first_alive_listing.try(:address)
|
149
|
+
port = first_alive_listing.try(:port)
|
150
|
+
@stats.server = [port, host]
|
151
|
+
return "tcp://#{host}:#{port}"
|
152
|
+
end
|
153
|
+
|
154
|
+
host = options[:host]
|
155
|
+
port = options[:port]
|
156
|
+
|
157
|
+
if host_alive?(host)
|
158
|
+
@stats.server = [port, host]
|
159
|
+
return "tcp://#{host}:#{port}"
|
160
|
+
end
|
161
|
+
|
162
|
+
sleep(1.0 / 100.0)
|
163
|
+
end
|
164
|
+
|
165
|
+
fail "Host not found for service #{service}"
|
166
|
+
end
|
167
|
+
|
168
|
+
def ping_port_open?(host)
|
169
|
+
Ping.new(host, ping_port.to_i).online?
|
170
|
+
end
|
171
|
+
|
172
|
+
def rcv_timeout
|
173
|
+
@rcv_timeout ||= begin
|
174
|
+
case
|
175
|
+
when options[:timeout] then
|
176
|
+
options[:timeout]
|
177
|
+
when ENV.key?("PB_ZMQ_CLIENT_RCV_TIMEOUT") then
|
178
|
+
ENV["PB_ZMQ_CLIENT_RCV_TIMEOUT"].to_i
|
179
|
+
else
|
180
|
+
300_000 # 300 seconds
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Trying a number of times, attempt to get a response from the server.
|
186
|
+
# If we haven't received a legitimate response in the CLIENT_RETRIES number
|
187
|
+
# of retries, fail the request.
|
188
|
+
#
|
189
|
+
def send_request_with_lazy_pirate
|
190
|
+
attempt = 0
|
191
|
+
|
192
|
+
begin
|
193
|
+
attempt += 1
|
194
|
+
send_request_with_timeout(attempt)
|
195
|
+
parse_response
|
196
|
+
rescue RequestTimeout
|
197
|
+
retry if attempt < CLIENT_RETRIES
|
198
|
+
failure(:RPC_FAILED, "The server repeatedly failed to respond within #{timeout} seconds")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def send_request_with_timeout(attempt = 0)
|
203
|
+
socket = create_socket
|
204
|
+
socket.setsockopt(::ZMQ::RCVTIMEO, rcv_timeout)
|
205
|
+
socket.setsockopt(::ZMQ::SNDTIMEO, snd_timeout)
|
206
|
+
|
207
|
+
logger.debug { sign_message("Sending Request (attempt #{attempt}, #{socket})") }
|
208
|
+
zmq_eagain_error_check(socket.send_string(@request_data), :socket_send_string)
|
209
|
+
logger.debug { sign_message("Waiting #{rcv_timeout}ms for response (attempt #{attempt}, #{socket})") }
|
210
|
+
zmq_eagain_error_check(socket.recv_string(@response_data = ""), :socket_recv_string)
|
211
|
+
logger.debug { sign_message("Response received (attempt #{attempt}, #{socket})") }
|
212
|
+
rescue ZmqEagainError
|
213
|
+
logger.debug { sign_message("Timed out waiting for response (attempt #{attempt}, #{socket})") }
|
214
|
+
raise RequestTimeout
|
215
|
+
ensure
|
216
|
+
logger.debug { sign_message("Closing Socket") }
|
217
|
+
zmq_error_check(socket.close, :socket_close) if socket
|
218
|
+
logger.debug { sign_message("Socket closed") }
|
219
|
+
end
|
220
|
+
|
221
|
+
def server_lookup_attempts
|
222
|
+
@server_lookup_attempts ||= [ENV["PB_ZMQ_CLIENT_SERVER_LOOKUP_ATTEMPTS"].to_i, 5].max
|
223
|
+
end
|
224
|
+
|
225
|
+
# The service we're attempting to connect to
|
226
|
+
#
|
227
|
+
def service
|
228
|
+
options[:service]
|
229
|
+
end
|
230
|
+
|
231
|
+
# Alias for ::Protobuf::Rpc::ServiceDirectory.instance
|
232
|
+
def service_directory
|
233
|
+
::Protobuf::Rpc.service_directory
|
234
|
+
end
|
235
|
+
|
236
|
+
def snd_timeout
|
237
|
+
@snd_timeout ||= begin
|
238
|
+
case
|
239
|
+
when options[:timeout] then
|
240
|
+
options[:timeout]
|
241
|
+
when ENV.key?("PB_ZMQ_CLIENT_SND_TIMEOUT") then
|
242
|
+
ENV["PB_ZMQ_CLIENT_SND_TIMEOUT"].to_i
|
243
|
+
else
|
244
|
+
300_000 # 300 seconds
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def socket_creation_attempts
|
250
|
+
@socket_creation_attempts ||= (ENV["PB_ZMQ_CLIENT_SOCKET_CREATION_ATTEMPTS"] || 5).to_i
|
251
|
+
end
|
252
|
+
|
253
|
+
def socket_to_available_server(socket)
|
254
|
+
check_available_response = ""
|
255
|
+
socket.setsockopt(::ZMQ::RCVTIMEO, check_available_rcv_timeout)
|
256
|
+
socket.setsockopt(::ZMQ::SNDTIMEO, check_available_snd_timeout)
|
257
|
+
zmq_recoverable_error_check(socket.send_string(::Protobuf::Rpc::Zmq::CHECK_AVAILABLE_MESSAGE), :socket_send_string)
|
258
|
+
zmq_recoverable_error_check(socket.recv_string(check_available_response), :socket_recv_string)
|
259
|
+
|
260
|
+
if check_available_response == ::Protobuf::Rpc::Zmq::NO_WORKERS_AVAILABLE
|
261
|
+
zmq_recoverable_error_check(socket.close, :socket_close)
|
262
|
+
end
|
263
|
+
|
264
|
+
socket.setsockopt(::ZMQ::RCVTIMEO, -1)
|
265
|
+
socket.setsockopt(::ZMQ::SNDTIMEO, -1)
|
266
|
+
socket
|
267
|
+
rescue ZmqRecoverableError
|
268
|
+
return nil # couldn't make a connection and need to try again
|
269
|
+
end
|
270
|
+
|
271
|
+
# Return the ZMQ Context to use for this process.
|
272
|
+
# If the context does not exist, create it, then register
|
273
|
+
# an exit block to ensure the context is terminated correctly.
|
274
|
+
#
|
275
|
+
def zmq_context(reload = false)
|
276
|
+
self.class.zmq_context(reload)
|
277
|
+
end
|
278
|
+
|
279
|
+
def zmq_eagain_error_check(return_code, source)
|
280
|
+
return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
|
281
|
+
|
282
|
+
if ::ZMQ::Util.errno == ::ZMQ::EAGAIN # rubocop:disable Style/GuardClause
|
283
|
+
fail ZmqEagainError, <<-ERROR
|
284
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
285
|
+
|
286
|
+
#{caller(1).join($INPUT_RECORD_SEPARATOR)}
|
287
|
+
ERROR
|
288
|
+
else
|
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
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def zmq_error_check(return_code, source)
|
298
|
+
return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
|
299
|
+
|
300
|
+
fail <<-ERROR
|
301
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
302
|
+
|
303
|
+
#{caller(1).join($INPUT_RECORD_SEPARATOR)}
|
304
|
+
ERROR
|
305
|
+
end
|
306
|
+
|
307
|
+
def zmq_recoverable_error_check(return_code, source)
|
308
|
+
return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
|
309
|
+
|
310
|
+
fail ZmqRecoverableError, <<-ERROR
|
311
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
312
|
+
|
313
|
+
#{caller(1).join($INPUT_RECORD_SEPARATOR)}
|
314
|
+
ERROR
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|