protobuffy 3.6.0 → 4.0.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.
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)