protobuf 3.3.6 → 3.4.0

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