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