protobuffy 3.6.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +67 -0
  4. data/.rubocop_todo.yml +145 -0
  5. data/.travis.yml +25 -5
  6. data/CHANGES.md +55 -0
  7. data/CONTRIBUTING.md +1 -1
  8. data/LICENSE.txt +17 -9
  9. data/README.md +13 -12
  10. data/Rakefile +15 -11
  11. data/bin/protoc-gen-ruby +8 -3
  12. data/bin/rpc_server +1 -0
  13. data/examples/lib/example/reverse-client.rb +2 -2
  14. data/install-protobuf.sh +28 -0
  15. data/lib/protobuf.rb +57 -53
  16. data/lib/protobuf/cli.rb +94 -74
  17. data/lib/protobuf/code_generator.rb +60 -9
  18. data/lib/protobuf/decoder.rb +19 -65
  19. data/lib/protobuf/deprecation.rb +117 -0
  20. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +11 -1
  21. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +55 -3
  22. data/lib/protobuf/encoder.rb +13 -53
  23. data/lib/protobuf/enum.rb +58 -63
  24. data/lib/protobuf/field.rb +4 -4
  25. data/lib/protobuf/field/base_field.rb +101 -173
  26. data/lib/protobuf/field/bool_field.rb +17 -11
  27. data/lib/protobuf/field/bytes_field.rb +21 -35
  28. data/lib/protobuf/field/double_field.rb +0 -1
  29. data/lib/protobuf/field/enum_field.rb +23 -22
  30. data/lib/protobuf/field/field_array.rb +5 -4
  31. data/lib/protobuf/field/fixed32_field.rb +1 -1
  32. data/lib/protobuf/field/fixed64_field.rb +0 -1
  33. data/lib/protobuf/field/float_field.rb +4 -1
  34. data/lib/protobuf/field/int32_field.rb +0 -1
  35. data/lib/protobuf/field/int64_field.rb +0 -1
  36. data/lib/protobuf/field/integer_field.rb +0 -1
  37. data/lib/protobuf/field/message_field.rb +13 -28
  38. data/lib/protobuf/field/sfixed32_field.rb +0 -1
  39. data/lib/protobuf/field/sfixed64_field.rb +0 -1
  40. data/lib/protobuf/field/signed_integer_field.rb +0 -1
  41. data/lib/protobuf/field/sint32_field.rb +0 -1
  42. data/lib/protobuf/field/sint64_field.rb +0 -1
  43. data/lib/protobuf/field/string_field.rb +2 -4
  44. data/lib/protobuf/field/uint32_field.rb +0 -1
  45. data/lib/protobuf/field/uint64_field.rb +0 -1
  46. data/lib/protobuf/field/varint_field.rb +30 -13
  47. data/lib/protobuf/generators/base.rb +30 -16
  48. data/lib/protobuf/generators/enum_generator.rb +6 -9
  49. data/lib/protobuf/generators/extension_generator.rb +1 -2
  50. data/lib/protobuf/generators/field_generator.rb +25 -13
  51. data/lib/protobuf/generators/file_generator.rb +157 -35
  52. data/lib/protobuf/generators/group_generator.rb +22 -17
  53. data/lib/protobuf/generators/message_generator.rb +13 -14
  54. data/lib/protobuf/generators/option_generator.rb +17 -0
  55. data/lib/protobuf/generators/printable.rb +12 -13
  56. data/lib/protobuf/generators/service_generator.rb +2 -3
  57. data/lib/protobuf/http.rb +2 -2
  58. data/lib/protobuf/lifecycle.rb +20 -33
  59. data/lib/protobuf/logging.rb +39 -0
  60. data/lib/protobuf/message.rb +114 -47
  61. data/lib/protobuf/message/fields.rb +170 -88
  62. data/lib/protobuf/message/serialization.rb +19 -18
  63. data/lib/protobuf/optionable.rb +53 -6
  64. data/lib/protobuf/rpc/buffer.rb +18 -19
  65. data/lib/protobuf/rpc/client.rb +22 -50
  66. data/lib/protobuf/rpc/connectors/base.rb +177 -12
  67. data/lib/protobuf/rpc/connectors/http.rb +14 -9
  68. data/lib/protobuf/rpc/connectors/ping.rb +89 -0
  69. data/lib/protobuf/rpc/connectors/socket.rb +13 -8
  70. data/lib/protobuf/rpc/connectors/zmq.rb +178 -73
  71. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +4 -1
  72. data/lib/protobuf/rpc/env.rb +12 -12
  73. data/lib/protobuf/rpc/error.rb +3 -3
  74. data/lib/protobuf/rpc/error/client_error.rb +4 -4
  75. data/lib/protobuf/rpc/error/server_error.rb +9 -9
  76. data/lib/protobuf/rpc/middleware/exception_handler.rb +6 -2
  77. data/lib/protobuf/rpc/middleware/logger.rb +8 -4
  78. data/lib/protobuf/rpc/middleware/request_decoder.rb +17 -21
  79. data/lib/protobuf/rpc/middleware/response_encoder.rb +22 -27
  80. data/lib/protobuf/rpc/middleware/statsd.rb +3 -3
  81. data/lib/protobuf/rpc/rpc.pb.rb +4 -1
  82. data/lib/protobuf/rpc/server.rb +1 -1
  83. data/lib/protobuf/rpc/servers/http/server.rb +19 -17
  84. data/lib/protobuf/rpc/servers/socket/server.rb +78 -70
  85. data/lib/protobuf/rpc/servers/socket/worker.rb +4 -4
  86. data/lib/protobuf/rpc/servers/socket_runner.rb +27 -15
  87. data/lib/protobuf/rpc/servers/zmq/broker.rb +70 -31
  88. data/lib/protobuf/rpc/servers/zmq/server.rb +55 -47
  89. data/lib/protobuf/rpc/servers/zmq/util.rb +14 -13
  90. data/lib/protobuf/rpc/servers/zmq/worker.rb +16 -16
  91. data/lib/protobuf/rpc/servers/zmq_runner.rb +26 -7
  92. data/lib/protobuf/rpc/service.rb +21 -27
  93. data/lib/protobuf/rpc/service_directory.rb +43 -27
  94. data/lib/protobuf/rpc/service_dispatcher.rb +9 -10
  95. data/lib/protobuf/rpc/service_filters.rb +32 -55
  96. data/lib/protobuf/rpc/stat.rb +4 -8
  97. data/lib/protobuf/socket.rb +1 -2
  98. data/lib/protobuf/tasks/compile.rake +3 -4
  99. data/lib/protobuf/varint.rb +9 -0
  100. data/lib/protobuf/varint_pure.rb +13 -0
  101. data/lib/protobuf/version.rb +1 -1
  102. data/lib/protobuf/zmq.rb +2 -2
  103. data/proto/google/protobuf/descriptor.proto +190 -31
  104. data/protobuffy.gemspec +30 -17
  105. data/spec/benchmark/tasks.rb +27 -19
  106. data/spec/bin/protoc-gen-ruby_spec.rb +11 -6
  107. data/spec/encoding/all_types_spec.rb +96 -84
  108. data/spec/encoding/extreme_values_spec.rb +0 -0
  109. data/spec/functional/class_inheritance_spec.rb +52 -0
  110. data/spec/functional/code_generator_spec.rb +38 -0
  111. data/spec/functional/socket_server_spec.rb +15 -15
  112. data/spec/functional/zmq_server_spec.rb +29 -27
  113. data/spec/lib/protobuf/cli_spec.rb +82 -67
  114. data/spec/lib/protobuf/code_generator_spec.rb +37 -10
  115. data/spec/lib/protobuf/enum_spec.rb +77 -46
  116. data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
  117. data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
  118. data/spec/lib/protobuf/field/enum_field_spec.rb +26 -0
  119. data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
  120. data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
  121. data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
  122. data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
  123. data/spec/lib/protobuf/field/int32_field_spec.rb +114 -1
  124. data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
  125. data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
  126. data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
  127. data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
  128. data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
  129. data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
  130. data/spec/lib/protobuf/field/string_field_spec.rb +44 -11
  131. data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
  132. data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
  133. data/spec/lib/protobuf/field_spec.rb +4 -6
  134. data/spec/lib/protobuf/generators/base_spec.rb +80 -13
  135. data/spec/lib/protobuf/generators/enum_generator_spec.rb +35 -21
  136. data/spec/lib/protobuf/generators/extension_generator_spec.rb +12 -13
  137. data/spec/lib/protobuf/generators/field_generator_spec.rb +73 -21
  138. data/spec/lib/protobuf/generators/file_generator_spec.rb +89 -6
  139. data/spec/lib/protobuf/generators/service_generator_spec.rb +25 -13
  140. data/spec/lib/protobuf/lifecycle_spec.rb +25 -20
  141. data/spec/lib/protobuf/message_spec.rb +578 -79
  142. data/spec/lib/protobuf/optionable_spec.rb +202 -26
  143. data/spec/lib/protobuf/rpc/client_spec.rb +16 -16
  144. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +167 -13
  145. data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +4 -5
  146. data/spec/lib/protobuf/rpc/connectors/http_spec.rb +13 -11
  147. data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
  148. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +6 -7
  149. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +35 -52
  150. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +10 -10
  151. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +11 -11
  152. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +23 -23
  153. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +11 -11
  154. data/spec/lib/protobuf/rpc/middleware/statsd_spec.rb +6 -6
  155. data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +47 -44
  156. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +6 -6
  157. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +12 -10
  158. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +11 -11
  159. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +7 -7
  160. data/spec/lib/protobuf/rpc/service_directory_spec.rb +47 -49
  161. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +8 -25
  162. data/spec/lib/protobuf/rpc/service_filters_spec.rb +102 -69
  163. data/spec/lib/protobuf/rpc/service_spec.rb +37 -36
  164. data/spec/lib/protobuf/rpc/stat_spec.rb +7 -9
  165. data/spec/lib/protobuf/varint_spec.rb +29 -0
  166. data/spec/lib/protobuf_spec.rb +55 -28
  167. data/spec/spec_helper.rb +12 -27
  168. data/spec/support/all.rb +0 -1
  169. data/spec/support/packed_field.rb +4 -3
  170. data/spec/support/{test → protos}/all_types.data.bin +0 -0
  171. data/spec/support/{test → protos}/all_types.data.txt +0 -0
  172. data/spec/support/{test → protos}/enum.pb.rb +8 -4
  173. data/spec/support/{test → protos}/enum.proto +4 -1
  174. data/spec/support/{test → protos}/extreme_values.data.bin +0 -0
  175. data/spec/support/protos/google_unittest.bin +0 -0
  176. data/spec/support/protos/google_unittest.pb.rb +798 -0
  177. data/spec/support/{test → protos}/google_unittest.proto +237 -66
  178. data/spec/support/protos/google_unittest_custom_options.bin +0 -0
  179. data/spec/support/protos/google_unittest_custom_options.pb.rb +268 -0
  180. data/spec/support/protos/google_unittest_custom_options.proto +424 -0
  181. data/spec/support/protos/google_unittest_import.pb.rb +55 -0
  182. data/spec/support/{test → protos}/google_unittest_import.proto +19 -10
  183. data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
  184. data/spec/support/{test → protos}/google_unittest_import_public.proto +8 -5
  185. data/spec/support/{test → protos}/multi_field_extensions.pb.rb +5 -2
  186. data/spec/support/{test → protos}/multi_field_extensions.proto +2 -0
  187. data/spec/support/{test → protos}/resource.pb.rb +47 -11
  188. data/spec/support/{test → protos}/resource.proto +24 -1
  189. data/spec/support/resource_service.rb +23 -0
  190. data/spec/support/server.rb +32 -61
  191. metadata +119 -59
  192. data/lib/protobuf/deprecator.rb +0 -42
  193. data/lib/protobuf/logger.rb +0 -93
  194. data/lib/protobuf/rpc/connector.rb +0 -21
  195. data/lib/protobuf/rpc/connectors/common.rb +0 -172
  196. data/spec/data/data.bin +0 -3
  197. data/spec/data/types.bin +0 -0
  198. data/spec/lib/protobuf/logger_spec.rb +0 -145
  199. data/spec/lib/protobuf/rpc/connector_spec.rb +0 -26
  200. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +0 -170
  201. data/spec/support/test/defaults.pb.rb +0 -25
  202. data/spec/support/test/defaults.proto +0 -9
  203. data/spec/support/test/extended.pb.rb +0 -22
  204. data/spec/support/test/extended.proto +0 -10
  205. data/spec/support/test/google_unittest.pb.rb +0 -543
  206. data/spec/support/test/google_unittest_import.pb.rb +0 -37
  207. data/spec/support/test/google_unittest_import_public.pb.rb +0 -8
  208. data/spec/support/test/resource_service.rb +0 -26
  209. data/spec/support/tolerance_matcher.rb +0 -40
@@ -4,8 +4,7 @@ module Protobuf
4
4
  module Rpc
5
5
  module Connectors
6
6
  class Socket < Base
7
- include Protobuf::Rpc::Connectors::Common
8
- include Protobuf::Logger::LogMethods
7
+ include Protobuf::Logging
9
8
 
10
9
  def send_request
11
10
  timeout_wrap do
@@ -24,21 +23,27 @@ module Protobuf
24
23
 
25
24
  def close_connection
26
25
  @socket.close
27
- log_debug { sign_message('Connector closed') }
26
+ logger.debug { sign_message('Connector closed') }
28
27
  end
29
28
 
30
29
  def connect_to_rpc_server
31
- @socket = TCPSocket.new(options[:host], options[:port])
32
- log_debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
30
+ @socket ||= TCPSocket.new(options[:host], options[:port])
31
+ logger.debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
33
32
  end
34
33
 
35
34
  # Method to determine error state, must be used with Connector api
36
35
  def error?
37
36
  return true if @error
38
- log_debug { sign_message("Error state : #{@socket.closed?}") }
37
+ logger.debug { sign_message("Error state : #{@socket.closed?}") }
39
38
  @socket.closed?
40
39
  end
41
40
 
41
+ def post_init
42
+ send_data unless error?
43
+ rescue => e
44
+ failure(:RPC_ERROR, "Connection error: #{e.message}")
45
+ end
46
+
42
47
  def read_data
43
48
  size_io = StringIO.new
44
49
 
@@ -51,7 +56,7 @@ module Protobuf
51
56
  end
52
57
 
53
58
  def read_response
54
- log_debug { sign_message("error? is #{error?}") }
59
+ logger.debug { sign_message("error? is #{error?}") }
55
60
  return if error?
56
61
  response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
57
62
  response_buffer << read_data
@@ -65,7 +70,7 @@ module Protobuf
65
70
  request_buffer.set_data(@request_data)
66
71
  @socket.write(request_buffer.write)
67
72
  @socket.flush
68
- log_debug { sign_message("write closed") }
73
+ logger.debug { sign_message("write closed") }
69
74
  end
70
75
  end
71
76
  end
@@ -1,33 +1,37 @@
1
- require 'protobuf/rpc/connectors/base'
2
- require 'protobuf/rpc/service_directory'
1
+ require "thread_safe"
2
+ require "protobuf/rpc/connectors/base"
3
+ require "protobuf/rpc/connectors/ping"
4
+ require "protobuf/rpc/service_directory"
3
5
 
4
6
  module Protobuf
5
7
  module Rpc
6
8
  module Connectors
7
9
  class Zmq < Base
8
-
9
10
  RequestTimeout = Class.new(RuntimeError)
11
+ ZmqRecoverableError = Class.new(RuntimeError)
12
+ ZmqEagainError = Class.new(RuntimeError)
10
13
 
11
14
  ##
12
15
  # Included Modules
13
16
  #
14
-
15
- include Protobuf::Rpc::Connectors::Common
16
- include Protobuf::Logger::LogMethods
17
+ include Protobuf::Logging
17
18
 
18
19
  ##
19
20
  # Class Constants
20
21
  #
21
-
22
22
  CLIENT_RETRIES = (ENV['PB_CLIENT_RETRIES'] || 3)
23
23
 
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 { |hash, key|
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
@@ -35,6 +39,9 @@ module Protobuf
35
39
  ##
36
40
  # Instance methods
37
41
  #
42
+ def log_signature
43
+ @_log_signature ||= "[client-#{self.class}]"
44
+ end
38
45
 
39
46
  # Start the request/response cycle. We implement the Lazy Pirate
40
47
  # req/reply reliability pattern as laid out in the ZMQ Guide, Chapter 4.
@@ -46,15 +53,32 @@ module Protobuf
46
53
  send_request_with_lazy_pirate unless error?
47
54
  end
48
55
 
49
- def log_signature
50
- @_log_signature ||= "[client-#{self.class}]"
51
- end
52
-
53
56
  private
54
57
 
55
58
  ##
56
59
  # Private Instance methods
57
60
  #
61
+ def check_available_rcv_timeout
62
+ @check_available_rcv_timeout ||= begin
63
+ case
64
+ when ENV.key?("PB_ZMQ_CLIENT_CHECK_AVAILABLE_RCV_TIMEOUT") then
65
+ ENV["PB_ZMQ_CLIENT_CHECK_AVAILABLE_RCV_TIMEOUT"].to_i
66
+ else
67
+ 200 # ms
68
+ end
69
+ end
70
+ end
71
+
72
+ def check_available_snd_timeout
73
+ @check_available_snd_timeout ||= begin
74
+ case
75
+ when ENV.key?("PB_ZMQ_CLIENT_CHECK_AVAILABLE_SND_TIMEOUT") then
76
+ ENV["PB_ZMQ_CLIENT_CHECK_AVAILABLE_SND_TIMEOUT"].to_i
77
+ else
78
+ 200 # ms
79
+ end
80
+ end
81
+ end
58
82
 
59
83
  def close_connection
60
84
  # The socket is automatically closed after every request.
@@ -64,26 +88,14 @@ module Protobuf
64
88
  # service. The LINGER is set to 0 so we can close immediately in
65
89
  # the event of a timeout
66
90
  def create_socket
67
- socket = nil
68
-
69
91
  begin
70
- server_uri = lookup_server_uri
71
-
72
92
  socket = zmq_context.socket(::ZMQ::REQ)
73
- socket.setsockopt(::ZMQ::LINGER, 0)
74
-
75
- log_debug { sign_message("Establishing connection: #{server_uri}") }
76
- zmq_error_check(socket.connect(server_uri), :socket_connect)
77
- log_debug { sign_message("Connection established to #{server_uri}") }
78
-
79
- if first_alive_load_balance?
80
- check_available_response = ""
81
- zmq_error_check(socket.send_string(::Protobuf::Rpc::Zmq::CHECK_AVAILABLE_MESSAGE), :socket_send_string)
82
- zmq_error_check(socket.recv_string(check_available_response), :socket_recv_string)
83
93
 
84
- if check_available_response == ::Protobuf::Rpc::Zmq::NO_WORKERS_AVAILABLE
85
- zmq_error_check(socket.close, :socket_close)
86
- end
94
+ if socket # Make sure the context builds the socket
95
+ server_uri = lookup_server_uri
96
+ socket.setsockopt(::ZMQ::LINGER, 0)
97
+ zmq_error_check(socket.connect(server_uri), :socket_connect)
98
+ socket = socket_to_available_server(socket) if first_alive_load_balance?
87
99
  end
88
100
  end while socket.try(:socket).nil?
89
101
 
@@ -96,38 +108,73 @@ module Protobuf
96
108
  !! @error
97
109
  end
98
110
 
111
+ def host_alive?(host)
112
+ return true unless ping_port_enabled?
113
+
114
+ if (last_response = self.class.ping_port_responses[host])
115
+ if (Time.now.to_i - last_response[:at]) <= host_alive_check_interval
116
+ return last_response[:ping_port_open]
117
+ end
118
+ end
119
+
120
+ ping_port_open = ping_port_open?(host)
121
+ self.class.ping_port_responses[host] = {
122
+ :at => Time.now.to_i,
123
+ :ping_port_open => ping_port_open,
124
+ }
125
+ ping_port_open
126
+ end
127
+
128
+ def host_alive_check_interval
129
+ @host_alive_check_interval ||= [ENV["PB_ZMQ_CLIENT_HOST_ALIVE_CHECK_INTERVAL"].to_i, 1].max
130
+ end
131
+
99
132
  # Lookup a server uri for the requested service in the service
100
133
  # directory. If the service directory is not running, default
101
134
  # to the host and port in the options
102
135
  #
103
136
  def lookup_server_uri
104
- 50.times do
105
- service_directory.all_listings_for(service).each do |listing|
106
- host = listing.try(:address)
107
- port = listing.try(:port)
108
- return "tcp://#{host}:#{port}" if host_alive?(host)
137
+ server_lookup_attempts.times do
138
+ first_alive_listing = service_directory.all_listings_for(service).find do |listing|
139
+ host_alive?(listing.try(:address))
140
+ end
141
+
142
+ if first_alive_listing
143
+ host = first_alive_listing.try(:address)
144
+ port = first_alive_listing.try(:port)
145
+ @stats.server = [port, host]
146
+ return "tcp://#{host}:#{port}"
109
147
  end
110
148
 
111
149
  host = options[:host]
112
150
  port = options[:port]
113
- return "tcp://#{host}:#{port}" if host_alive?(host)
114
151
 
115
- sleep(1.0/10.0) # not sure why sleeping at all, but should be way less than 1 second
152
+ if host_alive?(host)
153
+ @stats.server = [port, host]
154
+ return "tcp://#{host}:#{port}"
155
+ end
156
+
157
+ sleep(1.0 / 100.0)
116
158
  end
117
159
 
118
- raise "Host not found for service #{service}"
160
+ fail "Host not found for service #{service}"
119
161
  end
120
162
 
121
- def host_alive?(host)
122
- return true unless ping_port_enabled?
123
-
124
- socket = TCPSocket.new(host, ping_port.to_i)
163
+ def ping_port_open?(host)
164
+ Ping.new(host, ping_port.to_i).online?
165
+ end
125
166
 
126
- true
127
- rescue
128
- false
129
- ensure
130
- socket.close rescue nil
167
+ def rcv_timeout
168
+ @rcv_timeout ||= begin
169
+ case
170
+ when options[:timeout] then
171
+ options[:timeout]
172
+ when ENV.key?("PB_ZMQ_CLIENT_RCV_TIMEOUT") then
173
+ ENV["PB_ZMQ_CLIENT_RCV_TIMEOUT"].to_i
174
+ else
175
+ 300_000 # 300 seconds
176
+ end
177
+ end
131
178
  end
132
179
 
133
180
  # Trying a number of times, attempt to get a response from the server.
@@ -136,39 +183,38 @@ module Protobuf
136
183
  #
137
184
  def send_request_with_lazy_pirate
138
185
  attempt = 0
139
- timeout = options[:timeout].to_f
140
186
 
141
187
  begin
142
188
  attempt += 1
143
- send_request_with_timeout(timeout, attempt)
189
+ send_request_with_timeout(attempt)
144
190
  parse_response
145
191
  rescue RequestTimeout
146
192
  retry if attempt < CLIENT_RETRIES
147
- fail(:RPC_FAILED, "The server repeatedly failed to respond within #{timeout} seconds")
193
+ failure(:RPC_FAILED, "The server repeatedly failed to respond within #{timeout} seconds")
148
194
  end
149
195
  end
150
196
 
151
- def send_request_with_timeout(timeout, attempt = 0)
197
+ def send_request_with_timeout(attempt = 0)
152
198
  socket = create_socket
153
-
154
- poller = ::ZMQ::Poller.new
155
- poller.register_readable(socket)
156
-
157
- log_debug { sign_message("Sending Request (attempt #{attempt}, #{socket})") }
158
- zmq_error_check(socket.send_string(@request_data), :socket_send_string)
159
- log_debug { sign_message("Waiting #{timeout} seconds for response (attempt #{attempt}, #{socket})") }
160
-
161
- if poller.poll(timeout * 1000) == 1
162
- zmq_error_check(socket.recv_string(@response_data = ""), :socket_recv_string)
163
- log_debug { sign_message("Response received (attempt #{attempt}, #{socket})") }
164
- else
165
- log_debug { sign_message("Timed out waiting for response (attempt #{attempt}, #{socket})") }
166
- raise RequestTimeout
167
- end
199
+ socket.setsockopt(::ZMQ::RCVTIMEO, rcv_timeout)
200
+ socket.setsockopt(::ZMQ::SNDTIMEO, snd_timeout)
201
+
202
+ logger.debug { sign_message("Sending Request (attempt #{attempt}, #{socket})") }
203
+ zmq_eagain_error_check(socket.send_string(@request_data), :socket_send_string)
204
+ logger.debug { sign_message("Waiting #{rcv_timeout}ms for response (attempt #{attempt}, #{socket})") }
205
+ zmq_eagain_error_check(socket.recv_string(@response_data = ""), :socket_recv_string)
206
+ logger.debug { sign_message("Response received (attempt #{attempt}, #{socket})") }
207
+ rescue ZmqEagainError
208
+ logger.debug { sign_message("Timed out waiting for response (attempt #{attempt}, #{socket})") }
209
+ raise RequestTimeout
168
210
  ensure
169
- log_debug { sign_message("Closing Socket") }
211
+ logger.debug { sign_message("Closing Socket") }
170
212
  zmq_error_check(socket.close, :socket_close) if socket
171
- log_debug { sign_message("Socket closed") }
213
+ logger.debug { sign_message("Socket closed") }
214
+ end
215
+
216
+ def server_lookup_attempts
217
+ @server_lookup_attempts ||= [ENV["PB_ZMQ_CLIENT_SERVER_LOOKUP_ATTEMPTS"].to_i, 5].max
172
218
  end
173
219
 
174
220
  # The service we're attempting to connect to
@@ -179,7 +225,38 @@ module Protobuf
179
225
 
180
226
  # Alias for ::Protobuf::Rpc::ServiceDirectory.instance
181
227
  def service_directory
182
- ::Protobuf::Rpc::ServiceDirectory.instance
228
+ ::Protobuf::Rpc.service_directory
229
+ end
230
+
231
+ def snd_timeout
232
+ @snd_timeout ||= begin
233
+ case
234
+ when options[:timeout] then
235
+ options[:timeout]
236
+ when ENV.key?("PB_ZMQ_CLIENT_SND_TIMEOUT") then
237
+ ENV["PB_ZMQ_CLIENT_SND_TIMEOUT"].to_i
238
+ else
239
+ 300_000 # 300 seconds
240
+ end
241
+ end
242
+ end
243
+
244
+ def socket_to_available_server(socket)
245
+ check_available_response = ""
246
+ socket.setsockopt(::ZMQ::RCVTIMEO, check_available_rcv_timeout)
247
+ socket.setsockopt(::ZMQ::SNDTIMEO, check_available_snd_timeout)
248
+ zmq_recoverable_error_check(socket.send_string(::Protobuf::Rpc::Zmq::CHECK_AVAILABLE_MESSAGE), :socket_send_string)
249
+ zmq_recoverable_error_check(socket.recv_string(check_available_response), :socket_recv_string)
250
+
251
+ if check_available_response == ::Protobuf::Rpc::Zmq::NO_WORKERS_AVAILABLE
252
+ zmq_recoverable_error_check(socket.close, :socket_close)
253
+ end
254
+
255
+ socket.setsockopt(::ZMQ::RCVTIMEO, -1)
256
+ socket.setsockopt(::ZMQ::SNDTIMEO, -1)
257
+ socket
258
+ rescue ZmqRecoverableError
259
+ return nil # couldn't make a connection and need to try again
183
260
  end
184
261
 
185
262
  # Return the ZMQ Context to use for this process.
@@ -190,15 +267,43 @@ module Protobuf
190
267
  self.class.zmq_context
191
268
  end
192
269
 
193
- def zmq_error_check(return_code, source)
194
- unless ::ZMQ::Util.resultcode_ok?(return_code || -1)
195
- raise <<-ERROR
270
+ def zmq_eagain_error_check(return_code, source)
271
+ return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
272
+
273
+ if ::ZMQ::Util.errno == ::ZMQ::EAGAIN # rubocop:disable Style/GuardClause
274
+ fail ZmqEagainError, <<-ERROR
275
+ Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
276
+
277
+ #{caller(1).join($INPUT_RECORD_SEPARATOR)}
278
+ ERROR
279
+ else
280
+ fail <<-ERROR
196
281
  Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
197
282
 
198
- #{caller(1).join($/)}
283
+ #{caller(1).join($INPUT_RECORD_SEPARATOR)}
199
284
  ERROR
200
285
  end
201
286
  end
287
+
288
+ def zmq_error_check(return_code, source)
289
+ return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
290
+
291
+ fail <<-ERROR
292
+ Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
293
+
294
+ #{caller(1).join($INPUT_RECORD_SEPARATOR)}
295
+ ERROR
296
+ end
297
+
298
+ def zmq_recoverable_error_check(return_code, source)
299
+ return if ::ZMQ::Util.resultcode_ok?(return_code || -1)
300
+
301
+ fail ZmqRecoverableError, <<-ERROR
302
+ Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
303
+
304
+ #{caller(1).join($INPUT_RECORD_SEPARATOR)}
305
+ ERROR
306
+ end
202
307
  end
203
308
  end
204
309
  end
@@ -1,11 +1,14 @@
1
+ # encoding: utf-8
2
+
1
3
  ##
2
4
  # This file is auto-generated. DO NOT EDIT!
3
5
  #
4
- require 'protobuf/message'
6
+ require 'protobuf'
5
7
 
6
8
  module Protobuf
7
9
  module Rpc
8
10
  module DynamicDiscovery
11
+ ::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }
9
12
 
10
13
  ##
11
14
  # Enum Classes
@@ -16,19 +16,19 @@ module Protobuf
16
16
  #
17
17
  def self.hash_accessor(*names) #:nodoc:
18
18
  names.each do |name|
19
- class_eval <<-METHOD, __FILE__, __LINE__ + 1
20
- def #{name}
21
- self['#{name}']
22
- end
19
+ name_str = name.to_s.freeze
23
20
 
24
- def #{name}=(value)
25
- self['#{name}'] = value
26
- end
21
+ define_method name do
22
+ self[name_str]
23
+ end
27
24
 
28
- def #{name}?
29
- ! self['#{name}'].nil?
30
- end
31
- METHOD
25
+ define_method "#{name}=" do |value|
26
+ self[name_str] = value
27
+ end
28
+
29
+ define_method "#{name}?" do
30
+ !self[name_str].nil?
31
+ end
32
32
  end
33
33
  end
34
34
 
@@ -49,7 +49,7 @@ module Protobuf
49
49
  :service_name,
50
50
  :worker_id
51
51
 
52
- def initialize(options={})
52
+ def initialize(options = {})
53
53
  merge!(options)
54
54
 
55
55
  self['worker_id'] = ::Thread.current.object_id.to_s(16)