The Basic.Qos method is crucial to the successful operation of a Bunny
consumer because it controls the flow of messages from the server to
the client. The Bunny method Client#qos wraps Basic.Qos making it
simple to call once a Bunny client is instantiated. RabbitMQ v1.6.0
only supports the :prefetch_count argument to that method at this
time. Here is an example -
my_client.qos(:prefetch_count => 1)
or you could just do -
my_client.qos
because :prefetch_count => 1 is the default
Using the :prefetch_count option means that if you turn on
acknowledgements in your subscribe call -
my_queue.subscribe(:ack => true)
the server will only send the specified number of messages to the
client and then will wait until those messages have been acknowledged
-
my_queue.ack()
before it sends any more.
When a Bunny client subscribes to a queue, what it is doing under the
covers is sending the AMQP Basic.Consume method to the server to
register as a consumer on a particular queue. By default the server
will try to send as many messages as it can down the communication
channel. If your Bunny client can consume all of the messages before
it tries to do anything else, everything works well. However, if you
call another Bunny method before all of the messages on the queue have
been consumed, you will see errors raised.
The errors are caused because Bunny will receive messages out of
sequence. Most of the time, when you call a Bunny method a reply is
expected from the server to confirm that the call was successful. If
you don't use Client#qos what can happen is this -
1. Client subscribes to queue.
2. Server sends as many messages as it can.
3. Client calls another Bunny method in the subscribe block.
4. The reply to that method gets queued up behind all of the incoming
messages from the subscribe method.
5. Client reads next message and receives one from the subscribe.
6. Client raises error because the received message is not the reply
that was expected.
The way to avoid these out of sequence problems is to do something
like this -
========== Example consumer.rb ============
require 'bunny'
b = Bunny.new()
b.start
# Set Quality of Service
b.qos
q = b.queue
10.times { q.publish('Hey Ho') }
cnt = 0
q.subscribe(:ack => true) do |msg|
cnt += 1
msg_cnt = q.message_count
puts '************************'
puts "Message: #{cnt} - #{msg}"
puts "#{msg_cnt} message(s) left in the queue"
puts '************************'
if msg_cnt > 0
q.ack
else
q.unsubscribe
q.ack
break
end
end
============= Example end ==============
Ideally you don't want to be calling the Queue#message_count method
for every message in a large queue, but the code illustrates my point.
By setting the prefetch count to 1 the subscribe block can call
q.message_count and get a reply from the server. After that, q.ack is
called which will trigger the server to release the next set of
messages (1 in this case).
I hope that this will help Bunny users to get subscription working
more to their liking.
Regards,
Chris
_______________________________________________
bunny-amqp-devel mailing list
bunny-am...@rubyforge.org
http://rubyforge.org/mailman/listinfo/bunny-amqp-devel