krakow 0.2.2 → 0.3.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.
- data/CHANGELOG.md +16 -0
- data/CONTRIBUTING.md +25 -0
- data/LICENSE +13 -0
- data/README.md +62 -9
- data/krakow.gemspec +3 -1
- data/lib/krakow/command/cls.rb +3 -4
- data/lib/krakow/command/fin.rb +13 -4
- data/lib/krakow/command/identify.rb +22 -9
- data/lib/krakow/command/mpub.rb +14 -4
- data/lib/krakow/command/nop.rb +3 -4
- data/lib/krakow/command/pub.rb +15 -5
- data/lib/krakow/command/rdy.rb +13 -4
- data/lib/krakow/command/req.rb +14 -4
- data/lib/krakow/command/sub.rb +14 -4
- data/lib/krakow/command/touch.rb +13 -4
- data/lib/krakow/command.rb +25 -3
- data/lib/krakow/connection.rb +286 -60
- data/lib/krakow/connection_features/deflate.rb +26 -1
- data/lib/krakow/connection_features/snappy_frames.rb +34 -3
- data/lib/krakow/connection_features/ssl.rb +43 -1
- data/lib/krakow/connection_features.rb +1 -0
- data/lib/krakow/consumer.rb +162 -49
- data/lib/krakow/discovery.rb +17 -6
- data/lib/krakow/distribution/default.rb +61 -33
- data/lib/krakow/distribution.rb +107 -57
- data/lib/krakow/exceptions.rb +14 -0
- data/lib/krakow/frame_type/error.rb +13 -7
- data/lib/krakow/frame_type/message.rb +47 -4
- data/lib/krakow/frame_type/response.rb +14 -4
- data/lib/krakow/frame_type.rb +20 -8
- data/lib/krakow/producer/http.rb +95 -6
- data/lib/krakow/producer.rb +60 -17
- data/lib/krakow/utils/lazy.rb +99 -40
- data/lib/krakow/utils/logging.rb +11 -0
- data/lib/krakow/utils.rb +3 -0
- data/lib/krakow/version.rb +3 -1
- data/lib/krakow.rb +1 -0
- metadata +11 -11
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -34
- data/test/spec.rb +0 -81
- data/test/specs/consumer.rb +0 -49
- data/test/specs/http_producer.rb +0 -123
- 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
|
-
|
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
|
data/lib/krakow/consumer.rb
CHANGED
@@ -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
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
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
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
:
|
71
|
-
:
|
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
|
77
|
-
#
|
78
|
-
#
|
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
|
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
|
-
#
|
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 =
|
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
|
112
|
-
#
|
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[
|
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
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
|
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 ==
|
134
|
-
warn "Connection failure detected. Removing connection: #{key}"
|
135
|
-
|
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
|
-
|
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
|
-
#
|
160
|
-
#
|
161
|
-
#
|
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
|
data/lib/krakow/discovery.rb
CHANGED
@@ -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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
16
|
-
#
|
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 |
|
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
|
-
#
|
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
|
-
#
|
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
|
-
|
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
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
registry_info[:
|
91
|
-
registry_info[:
|
92
|
-
|
93
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
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
|
-
#
|
123
|
+
# All connections without RDY state
|
124
|
+
#
|
125
|
+
# @return [Array<Krakow::Connection>]
|
103
126
|
def waiting_connections
|
104
|
-
registry.find_all do |
|
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(
|
129
|
+
end.map{|conn_id, info| connection_lookup(conn_id) }.compact
|
107
130
|
end
|
108
131
|
|
109
|
-
#
|
132
|
+
# All connections with RDY state
|
133
|
+
#
|
134
|
+
# @return [Array<Krakow::Connection>]
|
110
135
|
def rdy_connections
|
111
|
-
registry.find_all do |
|
136
|
+
registry.find_all do |conn_id, info|
|
112
137
|
info[:ready] > 0
|
113
|
-
end.map(
|
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
|