bunny 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bunny.gemspec +2 -2
- data/examples/simple_08.rb +1 -1
- data/examples/simple_09.rb +1 -1
- data/examples/simple_ack_08.rb +1 -1
- data/examples/simple_ack_09.rb +1 -1
- data/examples/simple_consumer_08.rb +15 -9
- data/examples/simple_consumer_09.rb +15 -9
- data/examples/simple_fanout_08.rb +1 -1
- data/examples/simple_fanout_09.rb +1 -1
- data/examples/simple_headers_08.rb +1 -1
- data/examples/simple_headers_09.rb +1 -1
- data/examples/simple_publisher_08.rb +2 -2
- data/examples/simple_topic_08.rb +1 -1
- data/examples/simple_topic_09.rb +1 -1
- data/lib/bunny.rb +1 -1
- data/lib/bunny/client08.rb +115 -51
- data/lib/bunny/client09.rb +117 -53
- data/lib/bunny/queue08.rb +19 -5
- data/lib/bunny/queue09.rb +19 -5
- data/lib/qrack/client.rb +2 -2
- data/spec/spec_08/bunny_spec.rb +23 -4
- data/spec/spec_08/exchange_spec.rb +31 -23
- data/spec/spec_08/queue_spec.rb +4 -4
- data/spec/spec_09/bunny_spec.rb +23 -4
- data/spec/spec_09/exchange_spec.rb +31 -23
- data/spec/spec_09/queue_spec.rb +4 -4
- metadata +2 -2
data/lib/bunny/client09.rb
CHANGED
@@ -28,6 +28,9 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
|
|
28
28
|
* <tt>:logging => true or false (_default_)</tt> - If set to _true_, session information is sent
|
29
29
|
to STDOUT if <tt>:logfile</tt> has not been specified. Otherwise, session information is written to
|
30
30
|
<tt>:logfile</tt>.
|
31
|
+
* <tt>:frame_max => maximum frame size in bytes (default = 131072)</tt>
|
32
|
+
* <tt>:channel_max => maximum number of channels (default = 0 no maximum)</tt>
|
33
|
+
* <tt>:heartbeat => number of seconds (default = 0 no heartbeat)</tt>
|
31
34
|
|
32
35
|
=end
|
33
36
|
|
@@ -38,15 +41,21 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
|
|
38
41
|
@user = opts[:user] || 'guest'
|
39
42
|
@pass = opts[:pass] || 'guest'
|
40
43
|
@vhost = opts[:vhost] || '/'
|
41
|
-
@frame_max = opts[:frame_max] || 131072
|
42
|
-
@channel_max = opts[:channel_max] || 5
|
43
44
|
@logfile = opts[:logfile] || nil
|
44
45
|
@logging = opts[:logging] || false
|
45
|
-
|
46
|
+
@status = :not_connected
|
47
|
+
@frame_max = opts[:frame_max] || 131072
|
48
|
+
@channel_max = opts[:channel_max] || 5
|
49
|
+
@heartbeat = opts[:heartbeat] || 0
|
46
50
|
@logger = nil
|
47
51
|
create_logger if @logging
|
52
|
+
@channels = []
|
48
53
|
# Create channel 0
|
49
54
|
@channel = Bunny::Channel09.new(self, true)
|
55
|
+
@exchanges = {}
|
56
|
+
@queues = {}
|
57
|
+
@heartbeat_in = false
|
58
|
+
@connecting = false
|
50
59
|
end
|
51
60
|
|
52
61
|
=begin rdoc
|
@@ -85,18 +94,6 @@ Exchange
|
|
85
94
|
|
86
95
|
=== DESCRIPTION:
|
87
96
|
|
88
|
-
Returns hash of exchanges declared by Bunny.
|
89
|
-
|
90
|
-
=end
|
91
|
-
|
92
|
-
def exchanges
|
93
|
-
@exchanges ||= {}
|
94
|
-
end
|
95
|
-
|
96
|
-
=begin rdoc
|
97
|
-
|
98
|
-
=== DESCRIPTION:
|
99
|
-
|
100
97
|
Declares a queue to the broker/server. If the queue does not exist, a new one is created
|
101
98
|
using the arguments passed in. If the queue already exists, a reference to it is created, provided
|
102
99
|
that the arguments passed in do not conflict with the existing attributes of the queue. If an error
|
@@ -135,19 +132,16 @@ Queue
|
|
135
132
|
|
136
133
|
return queues[name] if queues.has_key?(name)
|
137
134
|
|
138
|
-
|
135
|
+
Bunny::Queue09.new(self, name, opts)
|
139
136
|
end
|
140
|
-
|
141
|
-
=begin rdoc
|
142
|
-
|
143
|
-
=== DESCRIPTION:
|
144
|
-
|
145
|
-
Returns hash of queues declared by Bunny.
|
146
|
-
|
147
|
-
=end
|
148
137
|
|
149
|
-
def
|
150
|
-
|
138
|
+
def send_heartbeat
|
139
|
+
# Create a new heartbeat frame
|
140
|
+
hb = Qrack::Transport09::Heartbeat.new('')
|
141
|
+
# Channel 0 must be used
|
142
|
+
switch_channel(0) if @channel.number > 0
|
143
|
+
# Send the heartbeat to server
|
144
|
+
send_frame(hb)
|
151
145
|
end
|
152
146
|
|
153
147
|
def send_frame(*args)
|
@@ -161,10 +155,27 @@ Returns hash of queues declared by Bunny.
|
|
161
155
|
nil
|
162
156
|
end
|
163
157
|
|
164
|
-
def next_frame
|
165
|
-
|
166
|
-
|
167
|
-
|
158
|
+
def next_frame(opts = {})
|
159
|
+
secs = opts[:timeout] || 0
|
160
|
+
|
161
|
+
begin
|
162
|
+
Timeout::timeout(secs) do
|
163
|
+
@frame = Qrack::Transport09::Frame.parse(buffer)
|
164
|
+
end
|
165
|
+
rescue Timeout::Error
|
166
|
+
return :timed_out
|
167
|
+
end
|
168
|
+
|
169
|
+
@logger.info("received") { @frame } if @logging
|
170
|
+
|
171
|
+
raise Bunny::ConnectionError, 'No connection to server' if (@frame.nil? and !connecting?)
|
172
|
+
|
173
|
+
if @frame.is_a?(Qrack::Transport09::Heartbeat)
|
174
|
+
@heartbeat_in = true
|
175
|
+
next_frame
|
176
|
+
end
|
177
|
+
|
178
|
+
@frame
|
168
179
|
end
|
169
180
|
|
170
181
|
def next_payload
|
@@ -173,6 +184,43 @@ Returns hash of queues declared by Bunny.
|
|
173
184
|
end
|
174
185
|
|
175
186
|
alias next_method next_payload
|
187
|
+
|
188
|
+
=begin rdoc
|
189
|
+
|
190
|
+
=== DESCRIPTION:
|
191
|
+
|
192
|
+
Checks to see whether or not an undeliverable message has been returned as a result of a publish
|
193
|
+
with the <tt>:immediate</tt> or <tt>:mandatory</tt> options.
|
194
|
+
|
195
|
+
==== OPTIONS:
|
196
|
+
|
197
|
+
* <tt>:timeout => number of seconds (default = 0.1) - The method will wait for a return
|
198
|
+
message until this timeout interval is reached.
|
199
|
+
|
200
|
+
==== RETURNS:
|
201
|
+
|
202
|
+
<tt>:no_return</tt> if message was not returned before timeout .
|
203
|
+
<tt>{:header, :return_details, :payload}</tt> if message is returned. <tt>:return_details</tt> is
|
204
|
+
a hash <tt>{:reply_code, :reply_text, :exchange, :routing_key}</tt>.
|
205
|
+
|
206
|
+
=end
|
207
|
+
|
208
|
+
def returned_message(opts = {})
|
209
|
+
secs = opts[:timeout] || 0.1
|
210
|
+
frame = next_frame(:timeout => secs)
|
211
|
+
|
212
|
+
if frame.is_a?(Symbol)
|
213
|
+
return :no_return if frame == :timed_out
|
214
|
+
end
|
215
|
+
|
216
|
+
method = frame.payload
|
217
|
+
header = next_payload
|
218
|
+
msg = next_payload
|
219
|
+
raise Bunny::MessageError, 'unexpected length' if msg.length < header.size
|
220
|
+
|
221
|
+
# Return the message and related info
|
222
|
+
{:header => header, :payload => msg, :return_details => method.arguments}
|
223
|
+
end
|
176
224
|
|
177
225
|
=begin rdoc
|
178
226
|
|
@@ -189,12 +237,9 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
|
|
189
237
|
|
190
238
|
def close
|
191
239
|
# Close all active channels
|
192
|
-
channels.
|
240
|
+
channels.each do |c|
|
193
241
|
c.close if c.open?
|
194
242
|
end
|
195
|
-
|
196
|
-
# Set client channel to zero
|
197
|
-
self.channel = channels[0]
|
198
243
|
|
199
244
|
# Close connection to AMQP server
|
200
245
|
close_connection
|
@@ -227,6 +272,8 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
|
|
227
272
|
=end
|
228
273
|
|
229
274
|
def start_session
|
275
|
+
@connecting = true
|
276
|
+
|
230
277
|
# Create/get socket
|
231
278
|
socket
|
232
279
|
|
@@ -236,12 +283,14 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
|
|
236
283
|
# Open connection
|
237
284
|
open_connection
|
238
285
|
|
239
|
-
# Open
|
240
|
-
|
241
|
-
|
286
|
+
# Open another channel because channel zero is used for specific purposes
|
287
|
+
c = create_channel()
|
288
|
+
c.open
|
242
289
|
|
290
|
+
@connecting = false
|
291
|
+
|
243
292
|
# return status
|
244
|
-
status
|
293
|
+
@status = :connected
|
245
294
|
end
|
246
295
|
|
247
296
|
alias start start_session
|
@@ -250,7 +299,7 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
|
|
250
299
|
|
251
300
|
=== DESCRIPTION:
|
252
301
|
|
253
|
-
Asks the broker to redeliver all unacknowledged messages on a
|
302
|
+
Asks the broker to redeliver all unacknowledged messages on a specified channel. Zero or
|
254
303
|
more messages may be redelivered.
|
255
304
|
|
256
305
|
==== Options:
|
@@ -376,22 +425,35 @@ after a rollback.
|
|
376
425
|
create_logger if @logging
|
377
426
|
end
|
378
427
|
|
379
|
-
def
|
380
|
-
|
381
|
-
end
|
382
|
-
|
383
|
-
def get_channel
|
384
|
-
channels.each_value do |c|
|
428
|
+
def create_channel
|
429
|
+
channels.each do |c|
|
385
430
|
return c if (!c.open? and c.number != 0)
|
386
431
|
end
|
387
432
|
# If no channel to re-use instantiate new one
|
388
433
|
Bunny::Channel09.new(self)
|
389
434
|
end
|
390
435
|
|
436
|
+
def switch_channel(chann)
|
437
|
+
if (0...channels.size).include? chann
|
438
|
+
@channel = channels[chann]
|
439
|
+
chann
|
440
|
+
else
|
441
|
+
raise RuntimeError, "Invalid channel number - #{chann}"
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def connecting?
|
446
|
+
connecting
|
447
|
+
end
|
448
|
+
|
391
449
|
def init_connection
|
392
450
|
write(Qrack::Protocol09::HEADER)
|
393
451
|
write([0, Qrack::Protocol09::VERSION_MAJOR, Qrack::Protocol09::VERSION_MINOR, Qrack::Protocol09::REVISION].pack('C4'))
|
394
|
-
|
452
|
+
|
453
|
+
frame = next_frame
|
454
|
+
if frame.nil? or !frame.payload.is_a?(Qrack::Protocol09::Connection::Start)
|
455
|
+
raise Bunny::ProtocolError, 'Connection initiation failed'
|
456
|
+
end
|
395
457
|
end
|
396
458
|
|
397
459
|
def open_connection
|
@@ -404,12 +466,14 @@ after a rollback.
|
|
404
466
|
)
|
405
467
|
)
|
406
468
|
|
407
|
-
|
408
|
-
|
409
|
-
|
469
|
+
frame = next_frame
|
470
|
+
raise Bunny::ProtocolError, "Connection failed - user: #{@user}, pass: #{@pass}" if frame.nil?
|
471
|
+
|
472
|
+
method = frame.payload
|
473
|
+
|
410
474
|
if method.is_a?(Qrack::Protocol09::Connection::Tune)
|
411
475
|
send_frame(
|
412
|
-
Qrack::Protocol09::Connection::TuneOk.new( :channel_max => @channel_max, :frame_max => @frame_max, :heartbeat =>
|
476
|
+
Qrack::Protocol09::Connection::TuneOk.new( :channel_max => @channel_max, :frame_max => @frame_max, :heartbeat => @heartbeat)
|
413
477
|
)
|
414
478
|
end
|
415
479
|
|
@@ -421,6 +485,9 @@ after a rollback.
|
|
421
485
|
end
|
422
486
|
|
423
487
|
def close_connection
|
488
|
+
# Set client channel to zero
|
489
|
+
switch_channel(0)
|
490
|
+
|
424
491
|
send_frame(
|
425
492
|
Qrack::Protocol09::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
|
426
493
|
)
|
@@ -446,8 +513,6 @@ after a rollback.
|
|
446
513
|
return @socket if @socket and (@status == :connected) and not @socket.closed?
|
447
514
|
|
448
515
|
begin
|
449
|
-
@status = :not_connected
|
450
|
-
|
451
516
|
# Attempt to connect.
|
452
517
|
@socket = timeout(CONNECT_TIMEOUT) do
|
453
518
|
TCPSocket.new(host, port)
|
@@ -456,7 +521,6 @@ after a rollback.
|
|
456
521
|
if Socket.constants.include? 'TCP_NODELAY'
|
457
522
|
@socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
458
523
|
end
|
459
|
-
@status = :connected
|
460
524
|
rescue => e
|
461
525
|
@status = :not_connected
|
462
526
|
raise Bunny::ServerDownError, e.message
|
data/lib/bunny/queue08.rb
CHANGED
@@ -214,17 +214,21 @@ processing. If error occurs, _Bunny_::_ProtocolError_ is raised.
|
|
214
214
|
* <tt>:exclusive => true or false (_default_)</tt> - Request exclusive consumer access, meaning
|
215
215
|
only this consumer can access the queue.
|
216
216
|
* <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
|
217
|
+
* <tt>:timeout => number of seconds (default = 0 no timeout) - The subscribe loop will continue to wait for
|
218
|
+
messages until terminated (Ctrl-C or kill command) or this timeout interval is reached.
|
217
219
|
|
218
220
|
==== RETURNS:
|
219
221
|
|
220
222
|
If <tt>:header => true</tt> returns hash <tt>{:header, :delivery_details, :payload}</tt> for each message.
|
221
223
|
<tt>:delivery_details</tt> is a hash <tt>{:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}</tt>.
|
222
224
|
If <tt>:header => false</tt> only message payload is returned.
|
225
|
+
If <tt>:timeout => > 0</tt> is reached returns :timed_out
|
223
226
|
|
224
227
|
=end
|
225
228
|
|
226
229
|
def subscribe(opts = {}, &blk)
|
227
230
|
consumer_tag = opts[:consumer_tag] || name
|
231
|
+
secs = opts[:timeout] || 0
|
228
232
|
|
229
233
|
# ignore the :nowait option if passed, otherwise program will hang waiting for a
|
230
234
|
# response from the server causing an error.
|
@@ -247,13 +251,19 @@ If <tt>:header => false</tt> only message payload is returned.
|
|
247
251
|
"Error subscribing to queue #{name}" unless
|
248
252
|
client.next_method.is_a?(Qrack::Protocol::Basic::ConsumeOk)
|
249
253
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
+
loop do
|
255
|
+
begin
|
256
|
+
Timeout::timeout(secs) do
|
257
|
+
@method = client.next_method
|
258
|
+
end
|
259
|
+
rescue Timeout::Error
|
260
|
+
return :timed_out
|
261
|
+
end
|
262
|
+
|
263
|
+
break if @method.is_a?(Qrack::Protocol::Basic::CancelOk)
|
254
264
|
|
255
265
|
# get delivery tag to use for acknowledge
|
256
|
-
self.delivery_tag = method.delivery_tag if ack
|
266
|
+
self.delivery_tag = @method.delivery_tag if ack
|
257
267
|
|
258
268
|
header = client.next_payload
|
259
269
|
msg = client.next_payload
|
@@ -287,6 +297,10 @@ the server will not send any more messages for that consumer.
|
|
287
297
|
opts.delete(:nowait)
|
288
298
|
|
289
299
|
client.send_frame( Qrack::Protocol::Basic::Cancel.new({ :consumer_tag => consumer_tag }.merge(opts)))
|
300
|
+
|
301
|
+
raise Bunny::ProtocolError,
|
302
|
+
"Error unsubscribing from queue #{name}" unless
|
303
|
+
client.next_method.is_a?(Qrack::Protocol::Basic::CancelOk)
|
290
304
|
|
291
305
|
end
|
292
306
|
|
data/lib/bunny/queue09.rb
CHANGED
@@ -216,17 +216,21 @@ processing. If error occurs, _Bunny_::_ProtocolError_ is raised.
|
|
216
216
|
* <tt>:exclusive => true or false (_default_)</tt> - Request exclusive consumer access, meaning
|
217
217
|
only this consumer can access the queue.
|
218
218
|
* <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
|
219
|
+
* <tt>:timeout => number of seconds (default = 0 no timeout) - The subscribe loop will continue to wait for
|
220
|
+
messages until terminated (Ctrl-C or kill command) or this timeout interval is reached.
|
219
221
|
|
220
222
|
==== RETURNS:
|
221
223
|
|
222
224
|
If <tt>:header => true</tt> returns hash <tt>{:header, :delivery_details, :payload}</tt> for each message.
|
223
225
|
<tt>:delivery_details</tt> is a hash <tt>{:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}</tt>.
|
224
226
|
If <tt>:header => false</tt> only message payload is returned.
|
227
|
+
If <tt>:timeout => > 0</tt> is reached returns :timed_out
|
225
228
|
|
226
229
|
=end
|
227
230
|
|
228
231
|
def subscribe(opts = {}, &blk)
|
229
232
|
consumer_tag = opts[:consumer_tag] || name
|
233
|
+
secs = opts[:timeout] || 0
|
230
234
|
|
231
235
|
# ignore the :nowait option if passed, otherwise program will hang waiting for a
|
232
236
|
# response from the server causing an error.
|
@@ -250,13 +254,19 @@ If <tt>:header => false</tt> only message payload is returned.
|
|
250
254
|
"Error subscribing to queue #{name}" unless
|
251
255
|
client.next_method.is_a?(Qrack::Protocol09::Basic::ConsumeOk)
|
252
256
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
+
loop do
|
258
|
+
begin
|
259
|
+
Timeout::timeout(secs) do
|
260
|
+
@method = client.next_method
|
261
|
+
end
|
262
|
+
rescue Timeout::Error
|
263
|
+
return :timed_out
|
264
|
+
end
|
265
|
+
|
266
|
+
break if @method.is_a?(Qrack::Protocol09::Basic::CancelOk)
|
257
267
|
|
258
268
|
# get delivery tag to use for acknowledge
|
259
|
-
self.delivery_tag = method.delivery_tag if ack
|
269
|
+
self.delivery_tag = @method.delivery_tag if ack
|
260
270
|
|
261
271
|
header = client.next_payload
|
262
272
|
msg = client.next_payload
|
@@ -290,6 +300,10 @@ the server will not send any more messages for that consumer.
|
|
290
300
|
opts.delete(:nowait)
|
291
301
|
|
292
302
|
client.send_frame( Qrack::Protocol09::Basic::Cancel.new({ :consumer_tag => consumer_tag }.merge(opts)))
|
303
|
+
|
304
|
+
raise Bunny::ProtocolError,
|
305
|
+
"Error unsubscribing from queue #{name}" unless
|
306
|
+
client.next_method.is_a?(Qrack::Protocol09::Basic::CancelOk)
|
293
307
|
|
294
308
|
end
|
295
309
|
|
data/lib/qrack/client.rb
CHANGED
@@ -5,8 +5,8 @@ module Qrack
|
|
5
5
|
CONNECT_TIMEOUT = 1.0
|
6
6
|
RETRY_DELAY = 10.0
|
7
7
|
|
8
|
-
attr_reader :status, :host, :vhost, :port, :logging, :spec
|
9
|
-
attr_accessor :channel, :logfile, :exchanges, :queues, :channels
|
8
|
+
attr_reader :status, :host, :vhost, :port, :logging, :spec, :heartbeat
|
9
|
+
attr_accessor :channel, :logfile, :exchanges, :queues, :channels, :heartbeat_in, :connecting
|
10
10
|
|
11
11
|
end
|
12
12
|
end
|
data/spec/spec_08/bunny_spec.rb
CHANGED
@@ -19,18 +19,37 @@ describe Bunny do
|
|
19
19
|
@b.status.should == :connected
|
20
20
|
end
|
21
21
|
|
22
|
+
it "should be able to create and open a new channel" do
|
23
|
+
c = @b.create_channel
|
24
|
+
c.number.should == 2
|
25
|
+
c.should be_an_instance_of(Bunny::Channel)
|
26
|
+
@b.channels.size.should == 3
|
27
|
+
c.open.should == :open_ok
|
28
|
+
@b.channel.number.should == 2
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should be able to switch between channels" do
|
32
|
+
@b.channel.number.should == 1
|
33
|
+
@b.switch_channel(0)
|
34
|
+
@b.channel.number.should == 0
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should raise an error if trying to switch to a non-existent channel" do
|
38
|
+
lambda { @b.switch_channel(5)}.should raise_error(RuntimeError)
|
39
|
+
end
|
40
|
+
|
22
41
|
it "should be able to create an exchange" do
|
23
42
|
exch = @b.exchange('test_exchange')
|
24
|
-
exch.should be_an_instance_of
|
43
|
+
exch.should be_an_instance_of(Bunny::Exchange)
|
25
44
|
exch.name.should == 'test_exchange'
|
26
|
-
@b.exchanges.has_key?('test_exchange').should be
|
45
|
+
@b.exchanges.has_key?('test_exchange').should be(true)
|
27
46
|
end
|
28
47
|
|
29
48
|
it "should be able to create a queue" do
|
30
49
|
q = @b.queue('test1')
|
31
|
-
q.should be_an_instance_of
|
50
|
+
q.should be_an_instance_of(Bunny::Queue)
|
32
51
|
q.name.should == 'test1'
|
33
|
-
@b.queues.has_key?('test1').should be
|
52
|
+
@b.queues.has_key?('test1').should be(true)
|
34
53
|
end
|
35
54
|
|
36
55
|
it "should be able to set QoS" do
|