protobuf 3.3.6 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
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