I'm using streadway's amqp library to connect with a rabbitmq server. The library provides a channel.Consume() function which returns a "<- chan Delivery". It also provides a channel.Get() function which returns a "Delivery" among other things.
I've to implement a pop() functionality, and I'm using channel.Get(). However, the documentation says:
"In almost all cases, using Channel.Consume will be preferred."
Does the preferred here means recommended? Are there any disadvantages of using channel.Get() over channel.Consume()? If yes, how do I use channel.Consume() to implement a Pop() function?
As far as I can tell from the docs, yes, "preferred" does mean "recommended".
It seems that channel.Get()
doesn't provide as many features as channel.Consume()
, as well as being more readily usable in concurrent code due to it's returning a chan
of Delivery
, as opposed to each individual Delivery
separately.
The extra features mentioned are exclusive
, noLocal
and noWait
, as well as an optional Table
of args "that have specific semantics for the queue or server."
To implement a Pop()
function using channel.Consume()
you could, to link to some code fragments from the amqp example consumer, create a channel using the Consume()
function, create a function to handle the chan
of Delivery
which will actually implement your Pop()
functionality, then fire off the handle()
func in a goroutine
.
The key to this is that the channel (in the linked example) will block on sending if nothing is receiving. In the example, the handle()
func uses range
to process the entire channel until it's empty. Your Pop()
functionality may be better served by a function that just receives the last value from the chan
and returns it. Every time it's run it will return the latest Delivery
.
EDIT: Example function to receive the latest value from the channel and do stuff with it (This may not work for your use case, it may be more useful if the function sent the Delivery
on another chan
to another function to be processed. Also, I haven't tested the code below, it may be full of errors)
func handle(deliveries <-chan amqp.Delivery, done chan error) {
select {
case d = <-deliveries:
// Do stuff with the delivery
// Send any errors down the done chan. for example:
// done <- err
default:
done <- nil
}
}
It really depend of what are you trying to do. If you want to get only one message from queue (first one) you probably should use basic.get
, if you are planning to process all incoming messages from queue - basic.consume
is what you want.
Probably, it is not platform or library specific question but rather protocol understanding question.
UPD
I'm not familiar with it go language well, so I will try to give you some brief on AMQP details and describe use cases.
You may get in troubles and have an overhead with basic.consume
sometimes:
With basic.consume
you have such workflow:
basic.consume
method to notify broker that you want to receive messages
basic.consume-ok
message from brokerbasic.deliver
message from server
With basic.get
you have such workflow:
basic.get
to broker
basic.get-ok
method, which hold message(s) or basic.empty
method, which denote situation no message available on serverNote about synchronous and asynchronous methods: synchronous is expected to have some response, whether asynchronous doesn't
Note on basic.qos
method prefetch-count
property: it is ignored when no-ack
property is set on basic.consume
or basic.get
.
Spec has a note on basic.get
: "this method provides a direct access to the messages in a queue using a synchronous dialogue that is designed for specific types of application where synchronous functionality is more important than performance" which applies for continuous messages consumption.
My personal tests show that getting in row 1000 messages with basic.get
(0.38659715652466) is faster than getting 1000 messages with basic.consume
one by one (0.47398710250854) on RabbitMQ 3.0.1, Erlang R14B04 in average more than 15%.
If consume only one message in main thread is your case - probably you have to use basic.get
.
You still can consume only one message asynchronously, for example in separate thread or use some event mechanism. It would be better solution for you machine resource sometimes, but you have to take care about situation where no message available in queue.
If you have to process message one by one it is obvious that basic.consume
should be used, I think
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With