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