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.
Files changed (204) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rubocop.yml +70 -0
  4. data/.rubocop_todo.yml +145 -0
  5. data/.travis.yml +40 -0
  6. data/.yardopts +5 -0
  7. data/CHANGES.md +344 -0
  8. data/CONTRIBUTING.md +16 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +33 -0
  12. data/Rakefile +64 -0
  13. data/bin/protoc-gen-ruby +22 -0
  14. data/bin/rpc_server +5 -0
  15. data/install-protobuf.sh +28 -0
  16. data/lib/protobuf.rb +129 -0
  17. data/lib/protobuf/cli.rb +257 -0
  18. data/lib/protobuf/code_generator.rb +120 -0
  19. data/lib/protobuf/decoder.rb +28 -0
  20. data/lib/protobuf/deprecation.rb +117 -0
  21. data/lib/protobuf/descriptors.rb +3 -0
  22. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +62 -0
  23. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +301 -0
  24. data/lib/protobuf/encoder.rb +11 -0
  25. data/lib/protobuf/enum.rb +365 -0
  26. data/lib/protobuf/exceptions.rb +9 -0
  27. data/lib/protobuf/field.rb +74 -0
  28. data/lib/protobuf/field/base_field.rb +380 -0
  29. data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
  30. data/lib/protobuf/field/bool_field.rb +64 -0
  31. data/lib/protobuf/field/bytes_field.rb +78 -0
  32. data/lib/protobuf/field/double_field.rb +25 -0
  33. data/lib/protobuf/field/enum_field.rb +61 -0
  34. data/lib/protobuf/field/field_array.rb +104 -0
  35. data/lib/protobuf/field/field_hash.rb +122 -0
  36. data/lib/protobuf/field/fixed32_field.rb +25 -0
  37. data/lib/protobuf/field/fixed64_field.rb +28 -0
  38. data/lib/protobuf/field/float_field.rb +43 -0
  39. data/lib/protobuf/field/int32_field.rb +21 -0
  40. data/lib/protobuf/field/int64_field.rb +34 -0
  41. data/lib/protobuf/field/integer_field.rb +23 -0
  42. data/lib/protobuf/field/message_field.rb +51 -0
  43. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  44. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  45. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  46. data/lib/protobuf/field/sint32_field.rb +21 -0
  47. data/lib/protobuf/field/sint64_field.rb +21 -0
  48. data/lib/protobuf/field/string_field.rb +51 -0
  49. data/lib/protobuf/field/uint32_field.rb +21 -0
  50. data/lib/protobuf/field/uint64_field.rb +21 -0
  51. data/lib/protobuf/field/varint_field.rb +77 -0
  52. data/lib/protobuf/generators/base.rb +85 -0
  53. data/lib/protobuf/generators/enum_generator.rb +39 -0
  54. data/lib/protobuf/generators/extension_generator.rb +27 -0
  55. data/lib/protobuf/generators/field_generator.rb +193 -0
  56. data/lib/protobuf/generators/file_generator.rb +262 -0
  57. data/lib/protobuf/generators/group_generator.rb +122 -0
  58. data/lib/protobuf/generators/message_generator.rb +104 -0
  59. data/lib/protobuf/generators/option_generator.rb +17 -0
  60. data/lib/protobuf/generators/printable.rb +160 -0
  61. data/lib/protobuf/generators/service_generator.rb +50 -0
  62. data/lib/protobuf/lifecycle.rb +33 -0
  63. data/lib/protobuf/logging.rb +39 -0
  64. data/lib/protobuf/message.rb +260 -0
  65. data/lib/protobuf/message/fields.rb +233 -0
  66. data/lib/protobuf/message/serialization.rb +85 -0
  67. data/lib/protobuf/optionable.rb +70 -0
  68. data/lib/protobuf/rpc/buffer.rb +78 -0
  69. data/lib/protobuf/rpc/client.rb +140 -0
  70. data/lib/protobuf/rpc/connectors/base.rb +221 -0
  71. data/lib/protobuf/rpc/connectors/ping.rb +89 -0
  72. data/lib/protobuf/rpc/connectors/socket.rb +78 -0
  73. data/lib/protobuf/rpc/connectors/zmq.rb +319 -0
  74. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +50 -0
  75. data/lib/protobuf/rpc/env.rb +60 -0
  76. data/lib/protobuf/rpc/error.rb +28 -0
  77. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  78. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  79. data/lib/protobuf/rpc/middleware.rb +25 -0
  80. data/lib/protobuf/rpc/middleware/exception_handler.rb +40 -0
  81. data/lib/protobuf/rpc/middleware/logger.rb +95 -0
  82. data/lib/protobuf/rpc/middleware/request_decoder.rb +79 -0
  83. data/lib/protobuf/rpc/middleware/response_encoder.rb +83 -0
  84. data/lib/protobuf/rpc/middleware/runner.rb +18 -0
  85. data/lib/protobuf/rpc/rpc.pb.rb +64 -0
  86. data/lib/protobuf/rpc/rpc_method.rb +16 -0
  87. data/lib/protobuf/rpc/server.rb +39 -0
  88. data/lib/protobuf/rpc/servers/socket/server.rb +121 -0
  89. data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
  90. data/lib/protobuf/rpc/servers/socket_runner.rb +46 -0
  91. data/lib/protobuf/rpc/servers/zmq/broker.rb +194 -0
  92. data/lib/protobuf/rpc/servers/zmq/server.rb +321 -0
  93. data/lib/protobuf/rpc/servers/zmq/util.rb +48 -0
  94. data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
  95. data/lib/protobuf/rpc/servers/zmq_runner.rb +70 -0
  96. data/lib/protobuf/rpc/service.rb +172 -0
  97. data/lib/protobuf/rpc/service_directory.rb +261 -0
  98. data/lib/protobuf/rpc/service_dispatcher.rb +45 -0
  99. data/lib/protobuf/rpc/service_filters.rb +250 -0
  100. data/lib/protobuf/rpc/stat.rb +119 -0
  101. data/lib/protobuf/socket.rb +21 -0
  102. data/lib/protobuf/tasks.rb +1 -0
  103. data/lib/protobuf/tasks/compile.rake +80 -0
  104. data/lib/protobuf/varint.rb +20 -0
  105. data/lib/protobuf/varint_pure.rb +31 -0
  106. data/lib/protobuf/version.rb +3 -0
  107. data/lib/protobuf/wire_type.rb +10 -0
  108. data/lib/protobuf/zmq.rb +21 -0
  109. data/profile.html +5103 -0
  110. data/proto/dynamic_discovery.proto +44 -0
  111. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  112. data/proto/google/protobuf/descriptor.proto +779 -0
  113. data/proto/rpc.proto +69 -0
  114. data/protobuf-cucumber.gemspec +57 -0
  115. data/spec/benchmark/tasks.rb +143 -0
  116. data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
  117. data/spec/encoding/all_types_spec.rb +103 -0
  118. data/spec/encoding/extreme_values_spec.rb +0 -0
  119. data/spec/functional/class_inheritance_spec.rb +52 -0
  120. data/spec/functional/code_generator_spec.rb +58 -0
  121. data/spec/functional/socket_server_spec.rb +59 -0
  122. data/spec/functional/zmq_server_spec.rb +105 -0
  123. data/spec/lib/protobuf/cli_spec.rb +317 -0
  124. data/spec/lib/protobuf/code_generator_spec.rb +87 -0
  125. data/spec/lib/protobuf/enum_spec.rb +307 -0
  126. data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
  127. data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
  128. data/spec/lib/protobuf/field/enum_field_spec.rb +44 -0
  129. data/spec/lib/protobuf/field/field_array_spec.rb +105 -0
  130. data/spec/lib/protobuf/field/field_hash_spec.rb +168 -0
  131. data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
  132. data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
  133. data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
  134. data/spec/lib/protobuf/field/int32_field_spec.rb +120 -0
  135. data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
  136. data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
  137. data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
  138. data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
  139. data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
  140. data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
  141. data/spec/lib/protobuf/field/string_field_spec.rb +79 -0
  142. data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
  143. data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
  144. data/spec/lib/protobuf/field_spec.rb +192 -0
  145. data/spec/lib/protobuf/generators/base_spec.rb +154 -0
  146. data/spec/lib/protobuf/generators/enum_generator_spec.rb +82 -0
  147. data/spec/lib/protobuf/generators/extension_generator_spec.rb +42 -0
  148. data/spec/lib/protobuf/generators/field_generator_spec.rb +197 -0
  149. data/spec/lib/protobuf/generators/file_generator_spec.rb +119 -0
  150. data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
  151. data/spec/lib/protobuf/generators/service_generator_spec.rb +99 -0
  152. data/spec/lib/protobuf/lifecycle_spec.rb +94 -0
  153. data/spec/lib/protobuf/message_spec.rb +944 -0
  154. data/spec/lib/protobuf/optionable_spec.rb +265 -0
  155. data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
  156. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +226 -0
  157. data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
  158. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +34 -0
  159. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +110 -0
  160. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
  161. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
  162. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
  163. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +91 -0
  164. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
  165. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +43 -0
  166. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
  167. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
  168. data/spec/lib/protobuf/rpc/service_directory_spec.rb +293 -0
  169. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +35 -0
  170. data/spec/lib/protobuf/rpc/service_filters_spec.rb +517 -0
  171. data/spec/lib/protobuf/rpc/service_spec.rb +162 -0
  172. data/spec/lib/protobuf/rpc/stat_spec.rb +101 -0
  173. data/spec/lib/protobuf/varint_spec.rb +29 -0
  174. data/spec/lib/protobuf_spec.rb +105 -0
  175. data/spec/spec_helper.rb +42 -0
  176. data/spec/support/all.rb +6 -0
  177. data/spec/support/packed_field.rb +23 -0
  178. data/spec/support/protos/all_types.data.bin +0 -0
  179. data/spec/support/protos/all_types.data.txt +119 -0
  180. data/spec/support/protos/enum.pb.rb +63 -0
  181. data/spec/support/protos/enum.proto +37 -0
  182. data/spec/support/protos/extreme_values.data.bin +0 -0
  183. data/spec/support/protos/google_unittest.bin +0 -0
  184. data/spec/support/protos/google_unittest.pb.rb +798 -0
  185. data/spec/support/protos/google_unittest.proto +884 -0
  186. data/spec/support/protos/google_unittest_custom_options.bin +0 -0
  187. data/spec/support/protos/google_unittest_custom_options.pb.rb +361 -0
  188. data/spec/support/protos/google_unittest_custom_options.proto +424 -0
  189. data/spec/support/protos/google_unittest_import.pb.rb +55 -0
  190. data/spec/support/protos/google_unittest_import.proto +73 -0
  191. data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
  192. data/spec/support/protos/google_unittest_import_public.proto +41 -0
  193. data/spec/support/protos/map-test.bin +157 -0
  194. data/spec/support/protos/map-test.pb.rb +85 -0
  195. data/spec/support/protos/map-test.proto +68 -0
  196. data/spec/support/protos/multi_field_extensions.pb.rb +59 -0
  197. data/spec/support/protos/multi_field_extensions.proto +35 -0
  198. data/spec/support/protos/resource.pb.rb +172 -0
  199. data/spec/support/protos/resource.proto +137 -0
  200. data/spec/support/resource_service.rb +23 -0
  201. data/spec/support/server.rb +65 -0
  202. data/spec/support/test_app_file.rb +2 -0
  203. data/varint_prof.rb +82 -0
  204. 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