krakow 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/CONTRIBUTING.md +25 -0
  3. data/LICENSE +13 -0
  4. data/README.md +62 -9
  5. data/krakow.gemspec +3 -1
  6. data/lib/krakow/command/cls.rb +3 -4
  7. data/lib/krakow/command/fin.rb +13 -4
  8. data/lib/krakow/command/identify.rb +22 -9
  9. data/lib/krakow/command/mpub.rb +14 -4
  10. data/lib/krakow/command/nop.rb +3 -4
  11. data/lib/krakow/command/pub.rb +15 -5
  12. data/lib/krakow/command/rdy.rb +13 -4
  13. data/lib/krakow/command/req.rb +14 -4
  14. data/lib/krakow/command/sub.rb +14 -4
  15. data/lib/krakow/command/touch.rb +13 -4
  16. data/lib/krakow/command.rb +25 -3
  17. data/lib/krakow/connection.rb +286 -60
  18. data/lib/krakow/connection_features/deflate.rb +26 -1
  19. data/lib/krakow/connection_features/snappy_frames.rb +34 -3
  20. data/lib/krakow/connection_features/ssl.rb +43 -1
  21. data/lib/krakow/connection_features.rb +1 -0
  22. data/lib/krakow/consumer.rb +162 -49
  23. data/lib/krakow/discovery.rb +17 -6
  24. data/lib/krakow/distribution/default.rb +61 -33
  25. data/lib/krakow/distribution.rb +107 -57
  26. data/lib/krakow/exceptions.rb +14 -0
  27. data/lib/krakow/frame_type/error.rb +13 -7
  28. data/lib/krakow/frame_type/message.rb +47 -4
  29. data/lib/krakow/frame_type/response.rb +14 -4
  30. data/lib/krakow/frame_type.rb +20 -8
  31. data/lib/krakow/producer/http.rb +95 -6
  32. data/lib/krakow/producer.rb +60 -17
  33. data/lib/krakow/utils/lazy.rb +99 -40
  34. data/lib/krakow/utils/logging.rb +11 -0
  35. data/lib/krakow/utils.rb +3 -0
  36. data/lib/krakow/version.rb +3 -1
  37. data/lib/krakow.rb +1 -0
  38. metadata +11 -11
  39. data/Gemfile +0 -5
  40. data/Gemfile.lock +0 -34
  41. data/test/spec.rb +0 -81
  42. data/test/specs/consumer.rb +0 -49
  43. data/test/specs/http_producer.rb +0 -123
  44. data/test/specs/producer.rb +0 -20
@@ -1,24 +1,47 @@
1
+ require 'openssl'
2
+ require 'krakow'
3
+
1
4
  module Krakow
2
5
  module ConnectionFeatures
6
+ # SSL functionality
3
7
  module Ssl
8
+ # SSL-able IO
4
9
  class Io
5
10
 
6
11
  attr_reader :_socket
7
12
 
13
+ # Create new SSL-able IO
14
+ #
15
+ # @param io [IO] IO to wrap
16
+ # @param args [Hash]
17
+ # @option args [Hash] :ssl_context
18
+ # @return [Io]
8
19
  def initialize(io, args={})
9
20
  ssl_socket_arguments = [io]
10
21
  if(args[:ssl_context])
11
- # ssl_socket_arguments << SSLContext.new
22
+ validate_ssl_args!(args[:ssl_context])
23
+ context = OpenSSL::SSL::SSLContext.new
24
+ context.cert = OpenSSL::X509::Certificate.new(File.open(args[:ssl_context][:certificate]))
25
+ context.key = OpenSSL::PKey::RSA.new(File.open(args[:ssl_context][:key]))
26
+ ssl_socket_arguments << context
12
27
  end
13
28
  @_socket = Celluloid::IO::SSLSocket.new(*ssl_socket_arguments)
14
29
  _socket.sync = true
15
30
  _socket.connect
16
31
  end
17
32
 
33
+ # Proxy to underlying socket
34
+ #
35
+ # @param args [Object]
36
+ # @return [Object]
18
37
  def method_missing(*args)
19
38
  _socket.send(*args)
20
39
  end
21
40
 
41
+ # Receive bytes from the IO
42
+ #
43
+ # @param len [Integer] nuber of bytes
44
+ # @return [String]
22
45
  def recv(len)
23
46
  str = readpartial(len)
24
47
  if(len > str.length)
@@ -27,6 +50,25 @@ module Krakow
27
50
  str
28
51
  end
29
52
 
53
+ private
54
+
55
+ # Validate the SSL configuration provided
56
+ #
57
+ # @param args [Hash]
58
+ # @option args [String] :certificate path to certificate
59
+ # @option args [String] :key path to key
60
+ # @raise [ArgumentError, LoadError]
61
+ def validate_ssl_args!(args)
62
+ [:key, :certificate].each do |arg_key|
63
+ unless(args.has_key?(arg_key))
64
+ raise ArgumentError.new "The `:ssl_context` option requires `#{arg_key.inspect}` to be set"
65
+ end
66
+ unless(File.readable?(args[arg_key]))
67
+ raise LoadError.new "Unable to read the `#{arg_key.inspect}` file from the `:ssl_context` arguments"
68
+ end
69
+ end
70
+ end
71
+
30
72
  end
31
73
  end
32
74
  end
@@ -1,6 +1,7 @@
1
1
  require 'krakow'
2
2
 
3
3
  module Krakow
4
+ # Features that wrap the connection
4
5
  module ConnectionFeatures
5
6
  autoload :SnappyFrames, 'krakow/connection_features/snappy_frames'
6
7
  autoload :Deflate, 'krakow/connection_features/deflate'
@@ -1,7 +1,13 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
4
+ # Consume messages from a server
2
5
  class Consumer
3
6
 
4
7
  include Utils::Lazy
8
+ # @!parse include Krakow::Utils::Lazy::InstanceMethods
9
+ # @!parse extend Krakow::Utils::Lazy::ClassMethods
10
+
5
11
  include Celluloid
6
12
 
7
13
  trap_exit :connection_failure
@@ -9,25 +15,43 @@ module Krakow
9
15
 
10
16
  attr_reader :connections, :discovery, :distribution, :queue
11
17
 
18
+ # @!group Attributes
19
+
20
+ # @!macro [attach] attribute
21
+ # @!method $1
22
+ # @return [$2] the $1 $0
23
+ # @!method $1?
24
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
25
+ attribute :topic, String, :required => true
26
+ attribute :channel, String, :required => true
27
+ attribute :host, String
28
+ attribute :port, [String, Integer]
29
+ attribute :nsqlookupd, [Array, String]
30
+ attribute :max_in_flight, Integer, :default => 1
31
+ attribute :backoff_interval, Numeric
32
+ attribute :discovery_interval, Numeric, :default => 30
33
+ attribute :discovery_jitter, Numeric, :default => 10.0
34
+ attribute :notifier, Celluloid::Actor
35
+ attribute :connection_options, Hash, :default => ->{ Hash.new }
36
+
37
+ # @!endgroup
38
+
12
39
  def initialize(args={})
13
40
  super
14
- required! :topic, :channel
15
- optional :host, :port, :nslookupd, :nsqlookupd, :max_in_flight, :backoff_interval, :discovery_interval, :notifier, :connection_features
16
- arguments[:max_in_flight] ||= 1
17
- arguments[:discovery_interval] ||= 30
18
- arguments[:connection_features] ||= {}
19
- arguments[:nsqlookupd] ||= arguments[:nslookupd]
41
+ arguments[:connection_options] = {:features => {}, :config => {}}.merge(
42
+ arguments[:connection_options] || {}
43
+ )
20
44
  @connections = {}
21
45
  @distribution = Distribution::Default.new(
22
46
  :max_in_flight => max_in_flight,
23
- :backoff_interval => backoff_interval
47
+ :backoff_interval => backoff_interval,
48
+ :consumer => current_actor
24
49
  )
25
50
  @queue = Queue.new
26
51
  if(nsqlookupd)
27
52
  debug "Connections will be established via lookup #{nsqlookupd.inspect}"
28
53
  @discovery = Discovery.new(:nsqlookupd => nsqlookupd)
29
- init!
30
- every(discovery_interval){ init! }
54
+ discover
31
55
  elsif(host && port)
32
56
  debug "Connection will be established via direct connection #{host}:#{port}"
33
57
  connection = build_connection(host, port, queue)
@@ -42,10 +66,22 @@ module Krakow
42
66
  end
43
67
  end
44
68
 
69
+ # Returns [Krakow::Connection] associated to key
70
+ #
71
+ # @param key [Object] identifier
72
+ # @return [Krakow::Connection] associated connection
73
+ def connection(key)
74
+ @connections[key]
75
+ end
76
+
77
+ # @return [String] stringify object
45
78
  def to_s
46
79
  "<#{self.class.name}:#{object_id} T:#{topic} C:#{channel}>"
47
80
  end
48
81
 
82
+ # Instance destructor
83
+ #
84
+ # @return [nil]
49
85
  def goodbye_my_love!
50
86
  debug 'Tearing down consumer'
51
87
  connections.values.each do |con|
@@ -53,43 +89,79 @@ module Krakow
53
89
  end
54
90
  distribution.terminate if distribution && distribution.alive?
55
91
  info 'Consumer torn down'
92
+ nil
56
93
  end
57
94
 
58
- # host:: remote address
59
- # port:: remote port
60
- # queue:: message store queue
61
- # Build new `Connection`
95
+ # Build a new [Krakow::Connection]
96
+ #
97
+ # @param host [String] remote host
98
+ # @param port [String, Integer] remote port
99
+ # @param queue [Queue] queue for messages
100
+ # @return [Krakow::Connection, nil] new connection or nil
62
101
  def build_connection(host, port, queue)
63
- connection = Connection.new(
64
- :host => host,
65
- :port => port,
66
- :queue => queue,
67
- :notifier => notifier,
68
- :features => connection_features,
69
- :callback => {
70
- :actor => current_actor,
71
- :method => :process_message
72
- }
73
- )
102
+ begin
103
+ connection = Connection.new(
104
+ :host => host,
105
+ :port => port,
106
+ :queue => queue,
107
+ :topic => topic,
108
+ :channel => channel,
109
+ :notifier => notifier,
110
+ :features => connection_options[:features],
111
+ :features_args => connection_options[:config],
112
+ :callbacks => {
113
+ :handle => {
114
+ :actor => current_actor,
115
+ :method => :process_message
116
+ },
117
+ :reconnect => {
118
+ :actor => current_actor,
119
+ :method => :connection_reconnect
120
+ }
121
+ }
122
+ )
123
+ rescue => e
124
+ error "Failed to build connection (host: #{host} port: #{port} queue: #{queue}) - #{e.class}: #{e}"
125
+ debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
126
+ nil
127
+ end
74
128
  end
75
129
 
76
- # message:: FrameType
77
- # connection:: Connection
78
- # Process message if required
130
+ # Process a given message if required
131
+ #
132
+ # @param message [Krakow::FrameType]
133
+ # @param connection [Krakow::Connection]
134
+ # @return [Krakow::FrameType]
79
135
  def process_message(message, connection)
80
136
  if(message.is_a?(FrameType::Message))
81
- distribution.register_message(message, connection)
137
+ distribution.register_message(message, connection.identifier)
138
+ message.origin = current_actor
82
139
  end
83
140
  message
84
141
  end
85
142
 
86
- # connection:: Connection
143
+ # Action to take when a connection has reconnected
144
+ #
145
+ # @param connection [Krakow::Connection]
146
+ # @return [nil]
147
+ def connection_reconnect(connection)
148
+ connection.transmit(Command::Sub.new(:topic_name => topic, :channel_name => channel))
149
+ distribution.set_ready_for(connection)
150
+ nil
151
+ end
152
+
87
153
  # Send RDY for connection based on distribution rules
154
+ #
155
+ # @param connection [Krakow::Connection]
156
+ # @return [nil]
88
157
  def update_ready!(connection)
89
158
  distribution.set_ready_for(connection)
159
+ nil
90
160
  end
91
161
 
92
- # Requests lookup and adds connections
162
+ # Initialize the consumer by starting lookup and adding connections
163
+ #
164
+ # @return [nil]
93
165
  def init!
94
166
  debug 'Running consumer `init!` connection builds'
95
167
  found = discovery.lookup(topic)
@@ -97,7 +169,7 @@ module Krakow
97
169
  connection = nil
98
170
  found.each do |node|
99
171
  debug "Processing discovery result: #{node.inspect}"
100
- key = "#{node[:broadcast_address]}_#{node[:tcp_port]}"
172
+ key = Connection.identifier(node[:broadcast_address], node[:tcp_port], topic, channel)
101
173
  unless(connections[key])
102
174
  connection = build_connection(node[:broadcast_address], node[:tcp_port], queue)
103
175
  info "Registered new connection #{connection}" if register(connection)
@@ -106,16 +178,27 @@ module Krakow
106
178
  end
107
179
  end
108
180
  distribution.redistribute! if connection
181
+ nil
182
+ end
183
+
184
+ # Start the discovery interval lookup
185
+ #
186
+ # @return [nil]
187
+ def discover
188
+ init!
189
+ after(discovery_interval + (discovery_jitter * rand)){ discover }
109
190
  end
110
191
 
111
- # connection:: Connection
112
- # Registers connection with subscription. Returns false if failed
192
+ # Register connection with distribution
193
+ #
194
+ # @param connection [Krakow::Connection]
195
+ # @return [TrueClass, FalseClass] true if subscription was successful
113
196
  def register(connection)
114
197
  begin
115
198
  connection.init!
116
199
  connection.transmit(Command::Sub.new(:topic_name => topic, :channel_name => channel))
117
200
  self.link connection
118
- connections["#{connection.host}_#{connection.port}"] = connection
201
+ connections[connection.identifier] = connection
119
202
  distribution.add_connection(connection)
120
203
  true
121
204
  rescue Error::BadResponse => e
@@ -125,40 +208,56 @@ module Krakow
125
208
  end
126
209
  end
127
210
 
128
- # con:: actor
129
- # reason:: Exception
130
- # Remove connection from register if found
131
- def connection_failure(con, reason)
211
+ # Remove connection references when connection is terminated
212
+ #
213
+ # @param actor [Object] terminated actor
214
+ # @param reason [Exception] reason for termination
215
+ # @return [nil]
216
+ def connection_failure(actor, reason)
132
217
  connections.delete_if do |key, value|
133
- if(value == con)
134
- warn "Connection failure detected. Removing connection: #{key}"
135
- distribution.remove_connection(con)
218
+ if(value == actor && reason.nil?)
219
+ warn "Connection failure detected. Removing connection: #{key} - #{reason || 'no reason provided'}"
220
+ begin
221
+ distribution.remove_connection(key)
222
+ rescue Error::ConnectionUnavailable, Error::ConnectionFailure
223
+ warn 'Caught connection unavailability'
224
+ end
225
+ distribution.redistribute!
136
226
  true
137
227
  end
138
228
  end
139
- distribution.redistribute!
229
+ nil
140
230
  end
141
231
 
142
- # message_id:: Message ID (or message if you want to be lazy)
143
232
  # Confirm message has been processed
233
+ #
234
+ # @param message_id [String, Krakow::FrameType::Message]
235
+ # @return [TrueClass]
236
+ # @raise [KeyError] connection not found
144
237
  def confirm(message_id)
145
238
  message_id = message_id.message_id if message_id.respond_to?(:message_id)
146
239
  begin
147
240
  distribution.in_flight_lookup(message_id) do |connection|
148
241
  distribution.unregister_message(message_id)
149
242
  connection.transmit(Command::Fin.new(:message_id => message_id))
150
- distribution.success(connection)
243
+ distribution.success(connection.identifier)
151
244
  update_ready!(connection)
152
245
  end
153
246
  true
154
- rescue => e
247
+ rescue KeyError => e
248
+ error "Message confirmation failed: #{e}"
155
249
  abort e
250
+ rescue Error::ConnectionUnavailable => e
251
+ retry
156
252
  end
157
253
  end
254
+ alias_method :finish, :confirm
158
255
 
159
- # message_id:: Message ID
160
- # timeout:: Requeue timeout (default is none)
161
- # Requeue message (processing failure)
256
+ # Requeue message (generally due to processing failure)
257
+ #
258
+ # @param message_id [String, Krakow::FrameType::Message]
259
+ # @param timeout [Numeric]
260
+ # @return [TrueClass]
162
261
  def requeue(message_id, timeout=0)
163
262
  message_id = message_id.message_id if message_id.respond_to?(:message_id)
164
263
  distribution.in_flight_lookup(message_id) do |connection|
@@ -169,11 +268,25 @@ module Krakow
169
268
  :timeout => timeout
170
269
  )
171
270
  )
172
- distribution.failure(connection)
271
+ distribution.failure(connection.identifier)
173
272
  update_ready!(connection)
174
273
  end
175
274
  true
176
275
  end
177
276
 
277
+ # Touch message (to extend timeout)
278
+ #
279
+ # @param message_id [String, Krakow::FrameType::Message]
280
+ # @return [TrueClass]
281
+ def touch(message_id)
282
+ message_id = message_id.message_id if message_id.respond_to?(:message_id)
283
+ distribution.in_flight_lookup(message_id) do |connection|
284
+ connection.transmit(
285
+ Command::Touch.new(:message_id => message_id)
286
+ )
287
+ end
288
+ true
289
+ end
290
+
178
291
  end
179
292
  end
@@ -1,19 +1,30 @@
1
1
  require 'uri'
2
2
  require 'http'
3
3
  require 'multi_json'
4
+ require 'krakow'
4
5
 
5
6
  module Krakow
7
+
8
+ # Provides queue topic discovery
6
9
  class Discovery
7
10
 
8
11
  include Utils::Lazy
9
12
 
10
- def initialize(args={})
11
- super
12
- required! :nsqlookupd
13
- end
13
+ # @!group Attributes
14
+
15
+ # @!macro [attach] attribute
16
+ # @!method $1
17
+ # @return [$2] the $1 $0
18
+ # @!method $1?
19
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
20
+ attribute :nsqlookupd, [Array, String], :required => true
21
+
22
+ # @!endgroup
14
23
 
15
- # topic:: Topic name
16
- # Return list of end points with given topic name available
24
+ # Get list of end points with given topic name available
25
+ #
26
+ # @param topic [String] topic name
27
+ # @return [Array<Hash>]
17
28
  def lookup(topic)
18
29
  result = [nsqlookupd].flatten.map do |location|
19
30
  uri = URI.parse(location)
@@ -1,5 +1,9 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Distribution
5
+ # Default distribution implementation. This uses a round-robin
6
+ # approach for less than ideal states.
3
7
  class Default < Distribution
4
8
 
5
9
  attr_reader :less_than_ideal_stack, :watch_dog
@@ -9,7 +13,7 @@ module Krakow
9
13
  @ideal = registry.size < 1 ? 0 : max_in_flight / registry.size
10
14
  debug "Distribution calculated ideal: #{ideal}"
11
15
  if(less_than_ideal?)
12
- registry.each do |connection, reg_info|
16
+ registry.each do |connection_id, reg_info|
13
17
  reg_info[:ready] = 0
14
18
  end
15
19
  max_in_flight.times do
@@ -28,9 +32,9 @@ module Krakow
28
32
  @watch_dog = nil
29
33
  end
30
34
  connections.each do |connection|
31
- current_ready = ready_for(connection)
32
- calculate_ready!(connection)
33
- unless(current_ready == ready_for(connection))
35
+ current_ready = ready_for(connection.identifier)
36
+ calculate_ready!(connection.identifier)
37
+ unless(current_ready == ready_for(connection.identifier))
34
38
  debug "Redistribution ready setting update for connection #{connection}"
35
39
  set_ready_for(connection)
36
40
  end
@@ -38,12 +42,16 @@ module Krakow
38
42
  end
39
43
  end
40
44
 
41
- # Returns if `ideal` is less than 1
45
+ # Is ideal less than 1
46
+ #
47
+ # @return [TrueClass, FalseClass]
42
48
  def less_than_ideal?
43
49
  ideal < 1
44
50
  end
45
51
 
46
- # Returns next connection to receive RDY count
52
+ # Find next connection to receive RDY count
53
+ #
54
+ # @return [Krakow::Connection, nil]
47
55
  def less_than_ideal_ready!
48
56
  admit_defeat = false
49
57
  connection = nil
@@ -53,18 +61,24 @@ module Krakow
53
61
  admit_defeat = true
54
62
  end
55
63
  con = less_than_ideal_stack.pop
56
- connection = con unless registry_lookup(con)[:backoff_until] > Time.now.to_i
64
+ if(con)
65
+ unless(registry_lookup(con.identifier)[:backoff_until] > Time.now.to_i)
66
+ connection = con
67
+ end
68
+ end
57
69
  end
58
70
  if(connection)
59
- registry_lookup(connection)[:ready] = 1
71
+ registry_lookup(connection.identifier)[:ready] = 1
60
72
  connection
61
73
  end
62
74
  end
63
75
 
64
- # connection:: Connection
65
- # args:: optional args (:force)
66
- # Provides customized RDY set when less than ideal to round
67
- # robin through connections
76
+ # Adds extra functionality to provide round robin RDY setting
77
+ # when in less than ideal state
78
+ #
79
+ # @param connection [Krakow::Connection]
80
+ # @param args [Symbol]
81
+ # @return [Krakow::FrameType::Error, nil]
68
82
  def set_ready_for(connection, *args)
69
83
  super connection
70
84
  if(less_than_ideal? && !args.include?(:force))
@@ -79,51 +93,65 @@ module Krakow
79
93
  end
80
94
  end
81
95
 
82
- # connection:: Connection
83
96
  # Update connection ready count
84
- def calculate_ready!(connection)
85
- registry_info = registry_lookup(connection)
86
- unless(less_than_ideal?)
87
- registry_info[:ready] = ideal - registry_info[:in_flight]
88
- if(registry_info[:ready] < 0 || registry_info[:backoff_until] > Time.now.to_i)
89
- registry_info[:ready] = 0
90
- registry_info[:backoff_timer].cancel if registry[:backoff_timer]
91
- registry_info[:backoff_timer] = after(registry_info[:backoff_until] - Time.now.to_i) do
92
- calculate_ready!(connection)
93
- set_ready_for(conection) unless less_than_ideal?
97
+ # @param connection_identifier [String]
98
+ # @return [Integer, nil]
99
+ def calculate_ready!(connection_identifier)
100
+ begin
101
+ registry_info = registry_lookup(connection_identifier)
102
+ unless(less_than_ideal?)
103
+ registry_info[:ready] = ideal - registry_info[:in_flight]
104
+ if(registry_info[:ready] < 0 || registry_info[:backoff_until] > Time.now.to_i)
105
+ registry_info[:ready] = 0
106
+ registry_info[:backoff_timer].cancel if registry[:backoff_timer]
107
+ registry_info[:backoff_timer] = after(registry_info[:backoff_until] - Time.now.to_i) do
108
+ calculate_ready!(connection_identifier)
109
+ set_ready_for(connection_lookup(connection_identifier)) unless less_than_ideal?
110
+ end
94
111
  end
112
+ registry_info[:ready]
113
+ else
114
+ registry_info[:ready] = 0
95
115
  end
96
- registry_info[:ready]
97
- else
98
- registry_info[:ready] = 0
116
+ rescue Error::ConnectionFailure
117
+ warn 'Failed connection encountered!'
118
+ rescue Error::ConnectionUnavailable
119
+ warn 'Unavailable connection encountered!'
99
120
  end
100
121
  end
101
122
 
102
- # Returns all connections without RDY state
123
+ # All connections without RDY state
124
+ #
125
+ # @return [Array<Krakow::Connection>]
103
126
  def waiting_connections
104
- registry.find_all do |connection, info|
127
+ registry.find_all do |conn_id, info|
105
128
  info[:ready] < 1 && info[:in_flight] < 1 && info[:backoff_until] < Time.now.to_i
106
- end.map(&:first).compact
129
+ end.map{|conn_id, info| connection_lookup(conn_id) }.compact
107
130
  end
108
131
 
109
- # Returns all connections with RDY state
132
+ # All connections with RDY state
133
+ #
134
+ # @return [Array<Krakow::Connection>]
110
135
  def rdy_connections
111
- registry.find_all do |connection, info|
136
+ registry.find_all do |conn_id, info|
112
137
  info[:ready] > 0
113
- end.map(&:first).compact
138
+ end.map{|conn_id, info| connection_lookup(conn_id) }.compact
114
139
  end
115
140
 
116
141
  # Force a connection to give up RDY state so next in stack can receive
142
+ #
143
+ # @return [nil]
117
144
  def force_unready
118
145
  debug 'Forcing a connection into an unready state due to less than ideal state'
119
146
  connection = rdy_connections.shuffle.first
120
147
  if(connection)
121
148
  debug "Stripping RDY state from connection: #{connection}"
122
- calculate_ready!(connection)
149
+ calculate_ready!(connection.identifier)
123
150
  set_ready_for(connection)
124
151
  else
125
152
  warn "Failed to locate available connection for RDY aquisition!"
126
153
  end
154
+ nil
127
155
  end
128
156
 
129
157
  end