krakow 0.3.12 → 0.4.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.
- 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
|