krakow 0.3.12 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +4 -0
- data/krakow.gemspec +7 -4
- data/lib/krakow.rb +7 -0
- data/lib/krakow/command/auth.rb +1 -1
- data/lib/krakow/command/identify.rb +1 -1
- data/lib/krakow/command/mpub.rb +2 -2
- data/lib/krakow/command/pub.rb +1 -1
- data/lib/krakow/connection.rb +49 -107
- data/lib/krakow/consumer.rb +97 -42
- data/lib/krakow/consumer/queue.rb +151 -0
- data/lib/krakow/distribution.rb +29 -12
- data/lib/krakow/frame_type/message.rb +17 -2
- data/lib/krakow/ksocket.rb +102 -0
- data/lib/krakow/producer.rb +36 -19
- data/lib/krakow/producer/http.rb +6 -1
- data/lib/krakow/version.rb +1 -1
- metadata +47 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01fd8940f20cb30ff26c163b8851fa88cad2f986
|
4
|
+
data.tar.gz: d6f277aeaaaf5adcadf08dbfa51fd6baf5370218
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86b969cfe4a3894983809cbe142497a658fc5bf369021fc6294629cde4443646be242bc4c3a870dab1efcd2da1615d7ba89c30ad04806187fb8448633d897778
|
7
|
+
data.tar.gz: 793e1ae1de7689b41fdd8c495404c238f7acd77a4520a08d4803607815205ec21cce4008c01781cc974128f347347e40a397b1657019da02d0d3964481ca6ea9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## v0.4.0
|
2
|
+
* Prevent duplicate connection consumption loops (#23) (thanks @phopkins)
|
3
|
+
* Refactor connection implementation to prevent crashing blocks (#22) (thanks @phopkins)
|
4
|
+
* Properly calculate message sizes using byte length, not string length (#24) (thanks @phopkins)
|
5
|
+
* Clear responses prior to message transmission (#20) (thanks @i2amsam)
|
6
|
+
* Rebuild testing specs (not fully covered, but a good start)
|
7
|
+
* Consumer and Producer provide better connection failure recovery
|
8
|
+
* Fix in-flight issues within distribution on connection failures
|
9
|
+
|
10
|
+
_NOTE: Large portions of `Krakow::Connection` has been refactored_
|
11
|
+
|
1
12
|
## v0.3.12
|
2
13
|
* Update Consumer#confirm and Consumer#touch to rescue out lookups and abort
|
3
14
|
|
data/README.md
CHANGED
@@ -218,6 +218,8 @@ Or, run part of them:
|
|
218
218
|
bundle exec ruby test/specs/consumer_spec.rb
|
219
219
|
```
|
220
220
|
|
221
|
+
*NOTE*: the specs expect that `nsqd` and `nsqlookupd` are available in `$PATH`
|
222
|
+
|
221
223
|
### It doesn't work
|
222
224
|
|
223
225
|
Create an issue on the github repository
|
@@ -240,6 +242,8 @@ Create an issue, or even better, send a PR.
|
|
240
242
|
|
241
243
|
# Contributors
|
242
244
|
|
245
|
+
* Pete Hopkins (@phopkins)
|
246
|
+
* Sam Phillips (@i2amsam)
|
243
247
|
* Brendan Schwartz (@bschwartz)
|
244
248
|
* Thomas Holmes (@thomas-holmes)
|
245
249
|
* Jeremy Hinegardner (@copiousfreetime)
|
data/krakow.gemspec
CHANGED
@@ -10,10 +10,13 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.description = 'NSQ ruby library'
|
11
11
|
s.license = 'Apache 2.0'
|
12
12
|
s.require_path = 'lib'
|
13
|
-
s.
|
14
|
-
s.
|
15
|
-
s.
|
16
|
-
s.
|
13
|
+
s.add_runtime_dependency 'celluloid'
|
14
|
+
s.add_runtime_dependency 'http'
|
15
|
+
s.add_runtime_dependency 'multi_json'
|
16
|
+
s.add_runtime_dependency 'digest-crc'
|
17
|
+
s.add_development_dependency 'childprocess'
|
18
|
+
s.add_development_dependency 'snappy'
|
19
|
+
s.add_development_dependency 'minitest'
|
17
20
|
s.files = Dir['lib/**/*'] + %w(krakow.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
|
18
21
|
s.extra_rdoc_files = %w(CHANGELOG.md CONTRIBUTING.md LICENSE)
|
19
22
|
end
|
data/lib/krakow.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
require 'krakow/version'
|
2
|
+
require 'celluloid'
|
3
|
+
|
4
|
+
if(ENV['DEBUG'])
|
5
|
+
Celluloid.task_class = Celluloid::TaskThread
|
6
|
+
end
|
7
|
+
|
2
8
|
require 'celluloid/autostart'
|
3
9
|
require 'multi_json'
|
4
10
|
|
@@ -13,6 +19,7 @@ module Krakow
|
|
13
19
|
autoload :Distribution, 'krakow/distribution'
|
14
20
|
autoload :Error, 'krakow/exceptions'
|
15
21
|
autoload :FrameType, 'krakow/frame_type'
|
22
|
+
autoload :Ksocket, 'krakow/ksocket'
|
16
23
|
autoload :Producer, 'krakow/producer'
|
17
24
|
autoload :Utils, 'krakow/utils'
|
18
25
|
|
data/lib/krakow/command/auth.rb
CHANGED
data/lib/krakow/command/mpub.rb
CHANGED
@@ -19,9 +19,9 @@ module Krakow
|
|
19
19
|
def to_line
|
20
20
|
formatted_messages = messages.map do |message|
|
21
21
|
message = message.to_s
|
22
|
-
[message.
|
22
|
+
[message.bytesize, message].pack('l>a*')
|
23
23
|
end.join
|
24
|
-
[name, ' ', topic_name, "\n", formatted_messages.
|
24
|
+
[name, ' ', topic_name, "\n", formatted_messages.bytesize, messages.size, formatted_messages].pack('a*a*a*a*l>l>a*')
|
25
25
|
end
|
26
26
|
|
27
27
|
class << self
|
data/lib/krakow/command/pub.rb
CHANGED
data/lib/krakow/connection.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'krakow'
|
2
|
-
require 'celluloid/io'
|
3
2
|
|
4
3
|
module Krakow
|
5
4
|
|
@@ -21,7 +20,7 @@ module Krakow
|
|
21
20
|
# @!parse include Krakow::Utils::Lazy::InstanceMethods
|
22
21
|
# @!parse extend Krakow::Utils::Lazy::ClassMethods
|
23
22
|
|
24
|
-
include Celluloid
|
23
|
+
include Celluloid
|
25
24
|
|
26
25
|
# Available connection features
|
27
26
|
FEATURES = [
|
@@ -43,14 +42,14 @@ module Krakow
|
|
43
42
|
# List of features that may be enabled by the client
|
44
43
|
ENABLEABLE_FEATURES = [:tls_v1, :snappy, :deflate, :auth_required]
|
45
44
|
|
46
|
-
finalizer :
|
45
|
+
finalizer :connection_cleanup
|
47
46
|
|
48
47
|
# @return [Hash] current configuration for endpoint
|
49
48
|
attr_reader :endpoint_settings
|
50
|
-
# @return [
|
49
|
+
# @return [Ksocket] underlying socket like instance
|
51
50
|
attr_reader :socket
|
52
|
-
|
53
|
-
attr_reader :
|
51
|
+
# @return [TrueClass, FalseClass]
|
52
|
+
attr_reader :running
|
54
53
|
|
55
54
|
# @!group Attributes
|
56
55
|
|
@@ -64,7 +63,7 @@ module Krakow
|
|
64
63
|
attribute :topic, String
|
65
64
|
attribute :channel, String
|
66
65
|
attribute :version, String, :default => 'v2'
|
67
|
-
attribute :queue, Queue, :default => ->{ Queue.new }
|
66
|
+
attribute :queue, [Queue, Consumer::Queue], :default => ->{ Queue.new }
|
68
67
|
attribute :callbacks, Hash, :default => ->{ Hash.new }
|
69
68
|
attribute :responses, Queue, :default => ->{ Queue.new }
|
70
69
|
attribute :notifier, [Celluloid::Signals, Celluloid::Condition, Celluloid::Actor]
|
@@ -95,10 +94,6 @@ module Krakow
|
|
95
94
|
# @option args [Hash] :feature_args options for connection features
|
96
95
|
def initialize(args={})
|
97
96
|
super
|
98
|
-
@reconnect_notifier = Celluloid::Signals.new
|
99
|
-
@socket_retries = 0
|
100
|
-
@socket_max_retries = 10
|
101
|
-
@reconnect_pause = 0.5
|
102
97
|
@endpoint_settings = {}
|
103
98
|
@running = false
|
104
99
|
end
|
@@ -118,6 +113,7 @@ module Krakow
|
|
118
113
|
# @return [nil]
|
119
114
|
def init!
|
120
115
|
connect!
|
116
|
+
async.process_to_queue!
|
121
117
|
nil
|
122
118
|
end
|
123
119
|
|
@@ -126,13 +122,16 @@ module Krakow
|
|
126
122
|
# @param message [Krakow::Message] message to send
|
127
123
|
# @return [TrueClass, Krakow::FrameType] response if expected or true
|
128
124
|
def transmit(message)
|
125
|
+
unless(message.respond_to?(:to_line))
|
126
|
+
abort TypeError.new("Expecting type `Krakow::FrameType` but received `#{message.class}`")
|
127
|
+
end
|
129
128
|
output = message.to_line
|
130
129
|
response_wait = wait_time_for(message)
|
131
130
|
if(response_wait > 0)
|
132
131
|
transmit_with_response(message, response_wait)
|
133
132
|
else
|
134
133
|
debug ">>> #{output}"
|
135
|
-
|
134
|
+
socket.put(output)
|
136
135
|
true
|
137
136
|
end
|
138
137
|
end
|
@@ -142,8 +141,8 @@ module Krakow
|
|
142
141
|
# @param message [Krakow::Message] message to send
|
143
142
|
# @return [Krakow::FrameType] response
|
144
143
|
def transmit_with_response(message, wait_time)
|
145
|
-
safe_socket{|socket| socket.write(message.to_line) }
|
146
144
|
responses.clear
|
145
|
+
socket.put(message.to_line)
|
147
146
|
response = nil
|
148
147
|
(wait_time / response_interval).to_i.times do |i|
|
149
148
|
response = responses.pop unless responses.empty?
|
@@ -168,16 +167,11 @@ module Krakow
|
|
168
167
|
# Destructor method for cleanup
|
169
168
|
#
|
170
169
|
# @return [nil]
|
171
|
-
def
|
170
|
+
def connection_cleanup
|
172
171
|
debug 'Tearing down connection'
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
action.call
|
177
|
-
rescue IOError, SystemCallError => e
|
178
|
-
warn "Socket error encountered during teardown: #{e.class}: #{e}"
|
179
|
-
end
|
180
|
-
end
|
172
|
+
@running = false
|
173
|
+
if(connected?)
|
174
|
+
socket.terminate
|
181
175
|
end
|
182
176
|
@socket = nil
|
183
177
|
info 'Connection torn down'
|
@@ -190,22 +184,19 @@ module Krakow
|
|
190
184
|
# @raise [Error::ConnectionUnavailable] socket is closed
|
191
185
|
def receive
|
192
186
|
debug 'Read wait for frame start'
|
193
|
-
buf = socket.
|
187
|
+
buf = socket.get(8)
|
194
188
|
if(buf)
|
195
189
|
@receiving = true
|
196
190
|
debug "<<< #{buf.inspect}"
|
197
191
|
struct = FrameType.decode(buf)
|
198
192
|
debug "Decoded structure: #{struct.inspect}"
|
199
|
-
struct[:data] = socket.
|
193
|
+
struct[:data] = socket.get(struct[:size])
|
200
194
|
debug "<<< #{struct[:data].inspect}"
|
201
195
|
@receiving = false
|
202
196
|
frame = FrameType.build(struct)
|
203
197
|
debug "Struct: #{struct.inspect} Frame: #{frame.inspect}"
|
204
198
|
frame
|
205
199
|
else
|
206
|
-
if(socket.closed?)
|
207
|
-
abort Error::ConnectionUnavailable.new("#{self} encountered closed socket!")
|
208
|
-
end
|
209
200
|
nil
|
210
201
|
end
|
211
202
|
end
|
@@ -219,19 +210,20 @@ module Krakow
|
|
219
210
|
#
|
220
211
|
# @return [nil]
|
221
212
|
def process_to_queue!
|
222
|
-
@running
|
223
|
-
|
224
|
-
|
213
|
+
unless(@running)
|
214
|
+
@running = true
|
215
|
+
while(@running)
|
225
216
|
message = handle(receive)
|
226
217
|
if(message)
|
227
218
|
debug "Adding message to queue #{message}"
|
228
219
|
queue << message
|
229
|
-
notifier
|
220
|
+
if(notifier)
|
221
|
+
warn "Sending new message notification: #{notifier} - #{message}"
|
222
|
+
notifier.broadcast(message)
|
223
|
+
end
|
224
|
+
else
|
225
|
+
debug 'Received `nil` message. Ignoring.'
|
230
226
|
end
|
231
|
-
rescue Error::ConnectionUnavailable => e
|
232
|
-
warn "Failed to receive message: #{e.class} - #{e}"
|
233
|
-
@running = false
|
234
|
-
async.reconnect!
|
235
227
|
end
|
236
228
|
end
|
237
229
|
nil
|
@@ -270,7 +262,11 @@ module Krakow
|
|
270
262
|
callback = callbacks[type]
|
271
263
|
if(callback)
|
272
264
|
debug "Processing connection callback for #{type.inspect} (#{callback.inspect})"
|
273
|
-
callback[:actor].
|
265
|
+
if(callback[:actor].alive?)
|
266
|
+
callback[:actor].send(callback[:method], *(args + [current_actor]))
|
267
|
+
else
|
268
|
+
error "Expected actor for callback processing is not alive! (type: `#{type.inspect}`)"
|
269
|
+
end
|
274
270
|
else
|
275
271
|
debug "No connection callback defined for #{type.inspect}"
|
276
272
|
args.size == 1 ? args.first : args
|
@@ -313,7 +309,7 @@ module Krakow
|
|
313
309
|
ident = Command::Identify.new(
|
314
310
|
expected_features
|
315
311
|
)
|
316
|
-
|
312
|
+
socket.put(ident.to_line)
|
317
313
|
response = receive
|
318
314
|
if(expected_features[:feature_negotiation])
|
319
315
|
begin
|
@@ -387,87 +383,33 @@ module Krakow
|
|
387
383
|
|
388
384
|
# @return [TrueClass, FalseClass] underlying socket is connected
|
389
385
|
def connected?
|
390
|
-
socket && !socket.closed?
|
391
|
-
end
|
392
|
-
|
393
|
-
protected
|
394
|
-
|
395
|
-
# Destruct the underlying socket
|
396
|
-
#
|
397
|
-
# @return [nil]
|
398
|
-
def teardown_socket
|
399
|
-
if(socket && (socket.closed? || socket.eof?))
|
400
|
-
socket.close unless socket.closed?
|
401
|
-
@socket = nil
|
402
|
-
warn 'Existing socket instance has been destroyed from this connection'
|
403
|
-
end
|
404
|
-
nil
|
405
|
-
end
|
406
|
-
|
407
|
-
# Provides socket failure state handling around given block
|
408
|
-
#
|
409
|
-
# @yield [socket] execute within socket safety layer
|
410
|
-
# @yieldparam [socket] underlying socket
|
411
|
-
# @return [Object] result of executed block
|
412
|
-
def safe_socket(*args)
|
413
386
|
begin
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
result = yield socket if block_given?
|
418
|
-
result
|
419
|
-
rescue Error::ConnectionUnavailable, SystemCallError, IOError => e
|
420
|
-
warn "Safe socket encountered error (socket in failed state): #{e.class}: #{e}"
|
421
|
-
reconnect!
|
422
|
-
retry
|
423
|
-
rescue Celluloid::Error => e
|
424
|
-
warn "Internal error encountered. Allowing exception to bubble. #{e.class}: #{e}"
|
425
|
-
abort e
|
426
|
-
rescue Exception => e
|
427
|
-
warn "!!! Unexpected error encountered within safe socket: #{e.class}: #{e}"
|
428
|
-
raise
|
387
|
+
!!(socket && socket.alive?)
|
388
|
+
rescue Celluloid::DeadActorError
|
389
|
+
false
|
429
390
|
end
|
430
391
|
end
|
431
392
|
|
432
|
-
|
433
|
-
#
|
434
|
-
# @return [nil]
|
435
|
-
def reconnect!
|
436
|
-
begin
|
437
|
-
if(@socket_max_retries <= @socket_retries)
|
438
|
-
abort ConnectionFailure.new "Failed to re-establish connection after #{@socket_retries} tries."
|
439
|
-
end
|
440
|
-
pause_interval = @reconnect_pause * @socket_retries
|
441
|
-
@socket_retries += 1
|
442
|
-
warn "Pausing for #{pause_interval} seconds before reconnect"
|
443
|
-
sleep(pause_interval)
|
444
|
-
init!
|
445
|
-
@socket_retries = 0
|
446
|
-
rescue Celluloid::Error => e
|
447
|
-
warn "Internal error encountered. Allowing exception to bubble. #{e.class}: #{e}"
|
448
|
-
abort e
|
449
|
-
rescue SystemCallError, IOError => e
|
450
|
-
error "Reconnect error encountered: #{e.class} - #{e}"
|
451
|
-
retry
|
452
|
-
end
|
453
|
-
callback_for(:reconnect)
|
454
|
-
nil
|
455
|
-
end
|
393
|
+
protected
|
456
394
|
|
457
395
|
# Connect the underlying socket
|
458
396
|
#
|
459
397
|
# @return [nil]
|
460
398
|
def connect!
|
461
399
|
debug 'Initializing connection'
|
462
|
-
|
463
|
-
@
|
464
|
-
|
400
|
+
unless(@connecting)
|
401
|
+
@connecting = true
|
402
|
+
if(socket && socket.alive?)
|
403
|
+
socket.terminate
|
404
|
+
@socket = nil
|
405
|
+
end
|
406
|
+
@socket = Ksocket.new(:host => host, :port => port)
|
407
|
+
self.link socket
|
408
|
+
socket.put version.rjust(4).upcase
|
409
|
+
identify_and_negotiate
|
410
|
+
info 'Connection initialized'
|
411
|
+
@connecting = false
|
465
412
|
end
|
466
|
-
@socket = Celluloid::IO::TCPSocket.new(host, port)
|
467
|
-
safe_socket{|socket| socket.write version.rjust(4).upcase}
|
468
|
-
identify_and_negotiate
|
469
|
-
async.process_to_queue!
|
470
|
-
info 'Connection initialized'
|
471
413
|
nil
|
472
414
|
end
|
473
415
|
|
data/lib/krakow/consumer.rb
CHANGED
@@ -4,6 +4,8 @@ module Krakow
|
|
4
4
|
# Consume messages from a server
|
5
5
|
class Consumer
|
6
6
|
|
7
|
+
autoload :Queue, 'krakow/consumer/queue'
|
8
|
+
|
7
9
|
include Utils::Lazy
|
8
10
|
# @!parse include Krakow::Utils::Lazy::InstanceMethods
|
9
11
|
# @!parse extend Krakow::Utils::Lazy::ClassMethods
|
@@ -11,7 +13,7 @@ module Krakow
|
|
11
13
|
include Celluloid
|
12
14
|
|
13
15
|
trap_exit :connection_failure
|
14
|
-
finalizer :
|
16
|
+
finalizer :consumer_cleanup
|
15
17
|
|
16
18
|
attr_reader :connections, :discovery, :distribution, :queue
|
17
19
|
|
@@ -42,30 +44,53 @@ module Krakow
|
|
42
44
|
arguments[:connection_options] || {}
|
43
45
|
)
|
44
46
|
@connections = {}
|
47
|
+
@queue = Queue.new(
|
48
|
+
current_actor,
|
49
|
+
:removal_callback => :remove_message
|
50
|
+
)
|
45
51
|
@distribution = Distribution::Default.new(
|
46
52
|
:max_in_flight => max_in_flight,
|
47
53
|
:backoff_interval => backoff_interval,
|
48
54
|
:consumer => current_actor
|
49
55
|
)
|
50
|
-
@queue = Queue.new
|
51
56
|
if(nsqlookupd)
|
52
57
|
debug "Connections will be established via lookup #{nsqlookupd.inspect}"
|
53
58
|
@discovery = Discovery.new(:nsqlookupd => nsqlookupd)
|
54
59
|
discover
|
55
60
|
elsif(host && port)
|
56
|
-
|
57
|
-
connection = build_connection(host, port, queue)
|
58
|
-
if(register(connection))
|
59
|
-
info "Registered new connection #{connection}"
|
60
|
-
distribution.redistribute!
|
61
|
-
else
|
62
|
-
abort Error::ConnectionFailure.new("Failed to establish subscription at provided end point (#{host}:#{port}")
|
63
|
-
end
|
61
|
+
direct_connect
|
64
62
|
else
|
65
63
|
abort Error::ConfigurationError.new('No connection information provided!')
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
67
|
+
# @return [TrueClass, FalseClass] currently connected to at least
|
68
|
+
# one nsqd
|
69
|
+
def connected?
|
70
|
+
!!connections.values.any? do |con|
|
71
|
+
begin
|
72
|
+
con.connected?
|
73
|
+
rescue Celluloid::DeadActorError
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Connect to nsqd instance directly
|
80
|
+
#
|
81
|
+
# @return [Connection]
|
82
|
+
def direct_connect
|
83
|
+
debug "Connection will be established via direct connection #{host}:#{port}"
|
84
|
+
connection = build_connection(host, port, queue)
|
85
|
+
if(register(connection))
|
86
|
+
info "Registered new connection #{connection}"
|
87
|
+
distribution.redistribute!
|
88
|
+
else
|
89
|
+
abort Error::ConnectionFailure.new("Failed to establish subscription at provided end point (#{host}:#{port}")
|
90
|
+
end
|
91
|
+
connection
|
92
|
+
end
|
93
|
+
|
69
94
|
# Returns [Krakow::Connection] associated to key
|
70
95
|
#
|
71
96
|
# @param key [Object] identifier
|
@@ -82,12 +107,17 @@ module Krakow
|
|
82
107
|
# Instance destructor
|
83
108
|
#
|
84
109
|
# @return [nil]
|
85
|
-
def
|
110
|
+
def consumer_cleanup
|
86
111
|
debug 'Tearing down consumer'
|
112
|
+
if(distribution && distribution.alive?)
|
113
|
+
distribution.terminate
|
114
|
+
end
|
115
|
+
if(queue && queue.alive?)
|
116
|
+
queue.terminate
|
117
|
+
end
|
87
118
|
connections.values.each do |con|
|
88
119
|
con.terminate if con.alive?
|
89
120
|
end
|
90
|
-
distribution.terminate if distribution && distribution.alive?
|
91
121
|
info 'Consumer torn down'
|
92
122
|
nil
|
93
123
|
end
|
@@ -113,13 +143,11 @@ module Krakow
|
|
113
143
|
:handle => {
|
114
144
|
:actor => current_actor,
|
115
145
|
:method => :process_message
|
116
|
-
},
|
117
|
-
:reconnect => {
|
118
|
-
:actor => current_actor,
|
119
|
-
:method => :connection_reconnect
|
120
146
|
}
|
121
147
|
}
|
122
148
|
)
|
149
|
+
queue.register_connection(connection)
|
150
|
+
connection
|
123
151
|
rescue => e
|
124
152
|
error "Failed to build connection (host: #{host} port: #{port} queue: #{queue}) - #{e.class}: #{e}"
|
125
153
|
debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
@@ -132,22 +160,30 @@ module Krakow
|
|
132
160
|
# @param message [Krakow::FrameType]
|
133
161
|
# @param connection [Krakow::Connection]
|
134
162
|
# @return [Krakow::FrameType]
|
163
|
+
# @note If we receive a message that is already in flight, attempt
|
164
|
+
# to scrub message from wait queue. If message is found, retry
|
165
|
+
# distribution registration. If message is not found, assume it
|
166
|
+
# is currently being processed and do not allow new message to
|
167
|
+
# be queued
|
135
168
|
def process_message(message, connection)
|
169
|
+
discard = false
|
136
170
|
if(message.is_a?(FrameType::Message))
|
137
|
-
distribution.register_message(message, connection.identifier)
|
138
171
|
message.origin = current_actor
|
172
|
+
message.connection = connection
|
173
|
+
retried = false
|
174
|
+
begin
|
175
|
+
distribution.register_message(message, connection.identifier)
|
176
|
+
rescue KeyError => e
|
177
|
+
if(!retried && queue.scrub_duplicate_message(message))
|
178
|
+
retried = true
|
179
|
+
retry
|
180
|
+
else
|
181
|
+
error "Received message is currently in flight and not in wait queue. Discarding! (#{message})"
|
182
|
+
discard = true
|
183
|
+
end
|
184
|
+
end
|
139
185
|
end
|
140
|
-
message
|
141
|
-
end
|
142
|
-
|
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
|
186
|
+
discard ? nil : message
|
151
187
|
end
|
152
188
|
|
153
189
|
# Send RDY for connection based on distribution rules
|
@@ -214,17 +250,30 @@ module Krakow
|
|
214
250
|
# @param reason [Exception] reason for termination
|
215
251
|
# @return [nil]
|
216
252
|
def connection_failure(actor, reason)
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
end
|
225
|
-
distribution.redistribute!
|
226
|
-
true
|
253
|
+
if(reason && key = connections.key(actor))
|
254
|
+
warn "Connection failure detected. Removing connection: #{key} - #{reason}"
|
255
|
+
connections.delete(key)
|
256
|
+
begin
|
257
|
+
distribution.remove_connection(key)
|
258
|
+
rescue Error::ConnectionUnavailable, Error::ConnectionFailure
|
259
|
+
warn 'Caught connection unavailability'
|
227
260
|
end
|
261
|
+
queue.deregister_connection(key)
|
262
|
+
distribution.redistribute!
|
263
|
+
direct_connect unless discovery
|
264
|
+
end
|
265
|
+
nil
|
266
|
+
end
|
267
|
+
|
268
|
+
# Remove message
|
269
|
+
#
|
270
|
+
# @param messages [Array<FrameType::Message>]
|
271
|
+
# @return [NilClass]
|
272
|
+
# @note used mainly for queue callback
|
273
|
+
def remove_message(messages)
|
274
|
+
[messages].flatten.compact.each do |msg|
|
275
|
+
distribution.unregister_message(msg.message_id)
|
276
|
+
update_ready!(msg.connection)
|
228
277
|
end
|
229
278
|
nil
|
230
279
|
end
|
@@ -237,11 +286,12 @@ module Krakow
|
|
237
286
|
def confirm(message_id)
|
238
287
|
message_id = message_id.message_id if message_id.respond_to?(:message_id)
|
239
288
|
begin
|
240
|
-
|
241
|
-
distribution.
|
289
|
+
begin
|
290
|
+
connection = distribution.in_flight_lookup(message_id)
|
242
291
|
connection.transmit(Command::Fin.new(:message_id => message_id))
|
243
292
|
distribution.success(connection.identifier)
|
244
|
-
|
293
|
+
rescue => e
|
294
|
+
abort e
|
245
295
|
end
|
246
296
|
true
|
247
297
|
rescue KeyError => e
|
@@ -251,7 +301,12 @@ module Krakow
|
|
251
301
|
error "Lookup of message for confirmation failed! <Message ID: #{message_id} - Error: #{e}>"
|
252
302
|
abort e
|
253
303
|
rescue Error::ConnectionUnavailable => e
|
254
|
-
|
304
|
+
abort e
|
305
|
+
rescue Celluloid::DeadActorError
|
306
|
+
abort Error::ConnectionUnavailable.new
|
307
|
+
ensure
|
308
|
+
con = distribution.unregister_message(message_id)
|
309
|
+
update_ready!(con) if con
|
255
310
|
end
|
256
311
|
end
|
257
312
|
alias_method :finish, :confirm
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'krakow'
|
2
|
+
|
3
|
+
module Krakow
|
4
|
+
# Consume messages from a server
|
5
|
+
class Consumer
|
6
|
+
|
7
|
+
class Queue
|
8
|
+
|
9
|
+
include Celluloid
|
10
|
+
include Utils::Lazy
|
11
|
+
|
12
|
+
# @return [Consumer]
|
13
|
+
attr_reader :consumer
|
14
|
+
# @return [Array] order of message removal
|
15
|
+
attr_reader :pop_order
|
16
|
+
# @return [Symbol] callback method name
|
17
|
+
attr_reader :removal_callback
|
18
|
+
|
19
|
+
# Create new consumer queue instance
|
20
|
+
#
|
21
|
+
# @param consumer [Consumer]
|
22
|
+
# @return [self]
|
23
|
+
def initialize(consumer, *args)
|
24
|
+
opts = args.detect{|x| x.is_a?(Hash)}
|
25
|
+
@consumer = consumer
|
26
|
+
@removal_callback = opts[:removal_callback]
|
27
|
+
@messages = {}
|
28
|
+
@pop_order = []
|
29
|
+
@cleaner = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# Message container
|
33
|
+
#
|
34
|
+
# @yieldparam [Hash] messages
|
35
|
+
# @return [Hash] messages or block result
|
36
|
+
def messages
|
37
|
+
if(block_given?)
|
38
|
+
yield @messages
|
39
|
+
else
|
40
|
+
@messages
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Register a new connection
|
45
|
+
#
|
46
|
+
# @param connection [Connection]
|
47
|
+
# @return [TrueClass]
|
48
|
+
def register_connection(connection)
|
49
|
+
messages do |collection|
|
50
|
+
collection[connection.identifier] = []
|
51
|
+
end
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
# Remove connection registration and remove all messages
|
56
|
+
#
|
57
|
+
# @param identifier [String] connection identifier
|
58
|
+
# @return [Array<FrameType::Message>] messages queued for deregistered connection
|
59
|
+
def deregister_connection(identifier)
|
60
|
+
messages do |collection|
|
61
|
+
removed = collection.delete(identifier)
|
62
|
+
pop_order.delete(identifier)
|
63
|
+
removed
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Push new message into queue
|
68
|
+
#
|
69
|
+
# @param message [FrameType::Message]
|
70
|
+
# @return [self]
|
71
|
+
def push(message)
|
72
|
+
unless(message.is_a?(FrameType::Message))
|
73
|
+
abort TypeError.new "Expecting `FrameType::Message` but received `#{message.class}`!"
|
74
|
+
end
|
75
|
+
messages do |collection|
|
76
|
+
begin
|
77
|
+
collection[message.connection.identifier] << message
|
78
|
+
pop_order << message.connection.identifier
|
79
|
+
rescue Celluloid::DeadActorError
|
80
|
+
abort Error::ConnectionUnavailable.new
|
81
|
+
end
|
82
|
+
end
|
83
|
+
signal(:new_message)
|
84
|
+
current_actor
|
85
|
+
end
|
86
|
+
alias_method :<<, :push
|
87
|
+
alias_method :enq, :push
|
88
|
+
|
89
|
+
# Pop first item off the queue
|
90
|
+
#
|
91
|
+
# @return [Object]
|
92
|
+
def pop
|
93
|
+
message = nil
|
94
|
+
until(message)
|
95
|
+
wait(:new_message) if pop_order.empty?
|
96
|
+
messages do |collection|
|
97
|
+
key = pop_order.shift
|
98
|
+
if(key)
|
99
|
+
message = collection[key].shift
|
100
|
+
message = validate_message(message)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
message
|
105
|
+
end
|
106
|
+
alias_method :deq, :pop
|
107
|
+
|
108
|
+
# @return [Integer] number of queued messages
|
109
|
+
def size
|
110
|
+
messages do |collection|
|
111
|
+
collection.values.map(&:size).inject(&:+)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Remove duplicate message from queue if possible
|
116
|
+
#
|
117
|
+
# @param message [FrameType::Message]
|
118
|
+
# @return [TrueClass, FalseClass]
|
119
|
+
def scrub_duplicate_message(message)
|
120
|
+
messages do |collection|
|
121
|
+
idx = collection[message.connection.identifier].index do |msg|
|
122
|
+
msg.message_id == message.message_id
|
123
|
+
end
|
124
|
+
if(idx)
|
125
|
+
msg = collection[message.connection.identifier].delete_at(idx)
|
126
|
+
if(removal_callback)
|
127
|
+
consumer.send(removal_callback, [message])
|
128
|
+
end
|
129
|
+
true
|
130
|
+
else
|
131
|
+
false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Validate message
|
137
|
+
def validate_message(message)
|
138
|
+
if(message.instance_stamp > message.instance_stamp + (message.connection.endpoint_settings[:msg_timeout] / 1000.0))
|
139
|
+
warn "Message exceeded timeout! Discarding. (#{message})"
|
140
|
+
if(removal_callback)
|
141
|
+
consumer.send(removal_callback, [message])
|
142
|
+
end
|
143
|
+
nil
|
144
|
+
else
|
145
|
+
message
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
data/lib/krakow/distribution.rb
CHANGED
@@ -52,15 +52,24 @@ module Krakow
|
|
52
52
|
# Remove message metadata from registry
|
53
53
|
#
|
54
54
|
# @param message [Krakow::FrameType::Message, String] message or ID
|
55
|
-
# @return [Krakow::Connection]
|
55
|
+
# @return [Krakow::Connection, NilClass]
|
56
56
|
def unregister_message(message)
|
57
57
|
msg_id = message.respond_to?(:message_id) ? message.message_id : message.to_s
|
58
58
|
connection = connection_lookup(flight_record[msg_id])
|
59
|
-
registry_info = registry_lookup(connection.identifier)
|
60
59
|
flight_record.delete(msg_id)
|
61
|
-
|
62
|
-
|
63
|
-
|
60
|
+
if(connection)
|
61
|
+
begin
|
62
|
+
ident = connection.identifier
|
63
|
+
registry_info = registry_lookup(ident)
|
64
|
+
registry_info[:in_flight] -= 1
|
65
|
+
calculate_ready!(ident)
|
66
|
+
connection
|
67
|
+
rescue Celluloid::DeadActorError
|
68
|
+
warn 'Connection is dead. No recalculation applied on ready.'
|
69
|
+
end
|
70
|
+
else
|
71
|
+
warn 'No connection associated to message via lookup. No recalculation applied on ready.'
|
72
|
+
end
|
64
73
|
end
|
65
74
|
|
66
75
|
# Return the currently configured RDY value for given connnection
|
@@ -97,10 +106,14 @@ module Krakow
|
|
97
106
|
# @param connection_identifier [String]
|
98
107
|
# @return [Integer]
|
99
108
|
def register_message(message, connection_identifier)
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
109
|
+
if(flight_record[message.message_id])
|
110
|
+
abort KeyError.new "Message is already registered in flight record! (#{message.message_id})"
|
111
|
+
else
|
112
|
+
registry_info = registry_lookup(connection_identifier)
|
113
|
+
registry_info[:in_flight] += 1
|
114
|
+
flight_record[message.message_id] = connection_identifier
|
115
|
+
calculate_ready!(connection_identifier)
|
116
|
+
end
|
104
117
|
end
|
105
118
|
|
106
119
|
# Add connection to make available for RDY distribution
|
@@ -128,8 +141,8 @@ module Krakow
|
|
128
141
|
registry.delete(connection_identifier)
|
129
142
|
# remove any in flight messages
|
130
143
|
flight_record.delete_if do |k,v|
|
131
|
-
if(
|
132
|
-
warn "Removing in flight reference due to failed connection: #{
|
144
|
+
if(v == connection_identifier)
|
145
|
+
warn "Removing in flight reference due to failed connection: #{v}"
|
133
146
|
true
|
134
147
|
end
|
135
148
|
end
|
@@ -156,7 +169,11 @@ module Krakow
|
|
156
169
|
abort Krakow::Error::LookupFailed.new("Failed to locate in flight message (ID: #{msg_id})")
|
157
170
|
end
|
158
171
|
if(block_given?)
|
159
|
-
|
172
|
+
begin
|
173
|
+
yield connection
|
174
|
+
rescue => e
|
175
|
+
abort e
|
176
|
+
end
|
160
177
|
else
|
161
178
|
connection
|
162
179
|
end
|
@@ -5,8 +5,9 @@ module Krakow
|
|
5
5
|
# Message received from server
|
6
6
|
class Message < FrameType
|
7
7
|
|
8
|
-
# @return [
|
9
|
-
|
8
|
+
# @return [Float] time of message instance creation
|
9
|
+
attr_reader :instance_stamp
|
10
|
+
attr_accessor :origin, :connection
|
10
11
|
|
11
12
|
# @!group Attributes
|
12
13
|
|
@@ -22,6 +23,11 @@ module Krakow
|
|
22
23
|
|
23
24
|
# @!endgroup
|
24
25
|
|
26
|
+
def initialize(*args)
|
27
|
+
super
|
28
|
+
@instance_stamp = Time.now.to_f
|
29
|
+
end
|
30
|
+
|
25
31
|
# Message content
|
26
32
|
#
|
27
33
|
# @return [String]
|
@@ -38,6 +44,15 @@ module Krakow
|
|
38
44
|
@origin
|
39
45
|
end
|
40
46
|
|
47
|
+
# @return [Krakow::Connection]
|
48
|
+
def connection
|
49
|
+
unless(@connection)
|
50
|
+
error 'No origin connection has been specified for this message'
|
51
|
+
abort Krakow::Error::ConnectionNotFound.new('No connection specified for this message')
|
52
|
+
end
|
53
|
+
@connection
|
54
|
+
end
|
55
|
+
|
41
56
|
# Proxy to [Krakow::Consumer#confirm]
|
42
57
|
def confirm(*args)
|
43
58
|
origin.confirm(*[self, *args].compact)
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'krakow'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module Krakow
|
5
|
+
class Ksocket
|
6
|
+
|
7
|
+
include Utils::Lazy
|
8
|
+
include Celluloid
|
9
|
+
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :buffer
|
12
|
+
|
13
|
+
finalizer :closedown_socket
|
14
|
+
|
15
|
+
# Teardown helper
|
16
|
+
def closedown_socket
|
17
|
+
@writing = @reading = false
|
18
|
+
if(socket && !socket.closed?)
|
19
|
+
socket.close
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create new socket wrapper
|
24
|
+
#
|
25
|
+
# @param args [Hash]
|
26
|
+
# @option args [Socket-ish] :socket
|
27
|
+
# @option args [String] :host
|
28
|
+
# @option args [Integer] :port
|
29
|
+
# @return [self]
|
30
|
+
def initialize(args={})
|
31
|
+
if(args[:socket])
|
32
|
+
@socket = args[:socket]
|
33
|
+
else
|
34
|
+
unless([:host, :port].all?{|k| args.include?(k)})
|
35
|
+
raise ArgumentError.new 'Missing required arguments. Expecting `:socket` or `:host` and `:port`.'
|
36
|
+
end
|
37
|
+
@socket = TCPSocket.new(args[:host], args[:port])
|
38
|
+
end
|
39
|
+
@buffer = ''
|
40
|
+
async.read_loop
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [TrueClass, FalseClass] read loop enabled
|
44
|
+
def reading?
|
45
|
+
!!@reading
|
46
|
+
end
|
47
|
+
|
48
|
+
# Read from socket and push into local Queue
|
49
|
+
def read_loop
|
50
|
+
unless(reading?)
|
51
|
+
@reading = true
|
52
|
+
while(reading?)
|
53
|
+
res = defer do
|
54
|
+
Kernel.select([socket], nil, nil, nil)
|
55
|
+
socket{|s| s.readpartial(1024)}
|
56
|
+
end
|
57
|
+
if(res)
|
58
|
+
debug "Received content from socket: #{res.inspect}"
|
59
|
+
buffer << res
|
60
|
+
signal(:content_read)
|
61
|
+
else
|
62
|
+
debug 'No content received from socket read. Ignoring.'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Fetch bytes from socket
|
69
|
+
#
|
70
|
+
# @param n [Integer]
|
71
|
+
# @return [String]
|
72
|
+
def get(n)
|
73
|
+
until(buffer.length >= n)
|
74
|
+
wait(:content_read)
|
75
|
+
end
|
76
|
+
buffer.slice!(0, n)
|
77
|
+
end
|
78
|
+
alias_method :recv, :get
|
79
|
+
alias_method :read, :get
|
80
|
+
alias_method :sysread, :get
|
81
|
+
alias_method :readpartial, :get
|
82
|
+
|
83
|
+
# Push bytes to socket
|
84
|
+
#
|
85
|
+
# @param line [String]
|
86
|
+
# @return [Integer]
|
87
|
+
def put(line)
|
88
|
+
socket{|s| s.write(line)}
|
89
|
+
end
|
90
|
+
alias_method :write, :put
|
91
|
+
|
92
|
+
# @return [Socket]
|
93
|
+
def socket
|
94
|
+
if(block_given?)
|
95
|
+
yield @socket
|
96
|
+
else
|
97
|
+
@socket
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
data/lib/krakow/producer.rb
CHANGED
@@ -14,12 +14,13 @@ module Krakow
|
|
14
14
|
include Celluloid
|
15
15
|
|
16
16
|
trap_exit :connection_failure
|
17
|
-
finalizer :
|
17
|
+
finalizer :producer_cleanup
|
18
18
|
|
19
19
|
# set exclusive methods
|
20
20
|
exclusive :write
|
21
21
|
|
22
22
|
attr_reader :connection
|
23
|
+
attr_reader :notifier
|
23
24
|
|
24
25
|
# @!group Attributes
|
25
26
|
|
@@ -49,6 +50,7 @@ module Krakow
|
|
49
50
|
#
|
50
51
|
# @return nil
|
51
52
|
def connect
|
53
|
+
@connecting = true
|
52
54
|
info "Establishing connection to: #{host}:#{port}"
|
53
55
|
begin
|
54
56
|
con_args = connection_options[:options].dup.tap do |args|
|
@@ -62,13 +64,14 @@ module Krakow
|
|
62
64
|
end
|
63
65
|
end
|
64
66
|
@connection = Connection.new(con_args)
|
65
|
-
connection.init!
|
66
|
-
self.link connection
|
67
|
-
info "Connection established: #{connection}"
|
67
|
+
@connection.init!
|
68
|
+
self.link @connection
|
69
|
+
info "Connection established: #{@connection}"
|
68
70
|
nil
|
69
71
|
rescue => e
|
70
72
|
abort e
|
71
73
|
end
|
74
|
+
@connecting = false
|
72
75
|
end
|
73
76
|
|
74
77
|
# @return [String] stringify object
|
@@ -78,28 +81,38 @@ module Krakow
|
|
78
81
|
|
79
82
|
# @return [TrueClass, FalseClass] currently connected to server
|
80
83
|
def connected?
|
81
|
-
|
84
|
+
begin
|
85
|
+
!!(!@connecting &&
|
86
|
+
connection &&
|
87
|
+
connection.alive? &&
|
88
|
+
connection.connected?)
|
89
|
+
rescue Celluloid::DeadActorError
|
90
|
+
false
|
91
|
+
end
|
82
92
|
end
|
83
93
|
|
84
94
|
# Process connection failure and attempt reconnection
|
85
95
|
#
|
86
96
|
# @return [TrueClass]
|
87
|
-
def connection_failure(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
97
|
+
def connection_failure(obj, reason)
|
98
|
+
if(obj == connection && !reason.nil?)
|
99
|
+
begin
|
100
|
+
@connection = nil
|
101
|
+
warn "Connection failure detected for #{host}:#{port} - #{reason}"
|
102
|
+
obj.terminate if obj.alive?
|
103
|
+
connect
|
104
|
+
rescue => reason
|
105
|
+
warn "Failed to establish connection to #{host}:#{port}. Pausing #{reconnect_interval} before retry"
|
106
|
+
sleep reconnect_interval
|
107
|
+
retry
|
108
|
+
end
|
96
109
|
end
|
97
110
|
true
|
98
111
|
end
|
99
112
|
|
100
113
|
# Instance destructor
|
101
114
|
# @return nil
|
102
|
-
def
|
115
|
+
def producer_cleanup
|
103
116
|
debug 'Tearing down producer'
|
104
117
|
if(connection && connection.alive?)
|
105
118
|
connection.terminate
|
@@ -112,13 +125,15 @@ module Krakow
|
|
112
125
|
# Write message to server
|
113
126
|
#
|
114
127
|
# @param message [String] message to write
|
115
|
-
# @return [Krakow::FrameType
|
128
|
+
# @return [Krakow::FrameType, TrueClass]
|
129
|
+
# @note if connection response wait is set to 0, writes will
|
130
|
+
# return a `true` value on completion
|
116
131
|
# @raise [Krakow::Error::ConnectionUnavailable]
|
117
132
|
def write(*message)
|
118
133
|
if(message.empty?)
|
119
134
|
abort ArgumentError.new 'Expecting one or more messages to send. None provided.'
|
120
135
|
end
|
121
|
-
|
136
|
+
begin
|
122
137
|
if(message.size > 1)
|
123
138
|
debug 'Multiple message publish'
|
124
139
|
connection.transmit(
|
@@ -136,8 +151,10 @@ module Krakow
|
|
136
151
|
)
|
137
152
|
)
|
138
153
|
end
|
139
|
-
|
140
|
-
abort Error::ConnectionUnavailable.new '
|
154
|
+
rescue Celluloid::Task::TerminatedError
|
155
|
+
abort Error::ConnectionUnavailable.new 'Connection is currently unavailable'
|
156
|
+
rescue => e
|
157
|
+
abort e
|
141
158
|
end
|
142
159
|
end
|
143
160
|
|
data/lib/krakow/producer/http.rb
CHANGED
@@ -72,7 +72,12 @@ module Krakow
|
|
72
72
|
begin
|
73
73
|
response = MultiJson.load(response.body.to_s)
|
74
74
|
rescue MultiJson::LoadError
|
75
|
-
response = {
|
75
|
+
response = {
|
76
|
+
'status_code' => response.code,
|
77
|
+
'status_txt' => response.body.to_s,
|
78
|
+
'response' => response.body.to_s,
|
79
|
+
'data' => nil,
|
80
|
+
}
|
76
81
|
end
|
77
82
|
Response.new(response)
|
78
83
|
end
|
data/lib/krakow/version.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: krakow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: celluloid
|
14
|
+
name: celluloid
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -66,6 +66,48 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: childprocess
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: snappy
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
69
111
|
description: NSQ ruby library
|
70
112
|
email: code@chrisroberts.org
|
71
113
|
executables: []
|
@@ -99,6 +141,7 @@ files:
|
|
99
141
|
- lib/krakow/connection_features/snappy_frames.rb
|
100
142
|
- lib/krakow/connection_features/ssl.rb
|
101
143
|
- lib/krakow/consumer.rb
|
144
|
+
- lib/krakow/consumer/queue.rb
|
102
145
|
- lib/krakow/discovery.rb
|
103
146
|
- lib/krakow/distribution.rb
|
104
147
|
- lib/krakow/distribution/default.rb
|
@@ -107,6 +150,7 @@ files:
|
|
107
150
|
- lib/krakow/frame_type/error.rb
|
108
151
|
- lib/krakow/frame_type/message.rb
|
109
152
|
- lib/krakow/frame_type/response.rb
|
153
|
+
- lib/krakow/ksocket.rb
|
110
154
|
- lib/krakow/producer.rb
|
111
155
|
- lib/krakow/producer/http.rb
|
112
156
|
- lib/krakow/utils.rb
|