-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Acknowledgements #2
Comments
This is intentional, yes. In fact, an earlier version would only acknowledge the message if the callback returned
However, I'm open to feedback here. What kind of pattern are you trying to implement where you need to fail to acknowledge messages? ps. Complete implementations for manually ack-ing and nack-ing messages are actually still in the source code, they're just not exported. |
When data consistency is a must I would prefer to be on the safe side and acknowledge only after function finished whatever it supposed to do. For example message queues commonly used as buffer to organize mini-batching and insertion to a database. So if error happens in a callback then messages are not inserted to a database. But at the same time they are consumed from a queue. This essentially means that messages are lost... |
I suppose that in cases like that I would handle errors at the application level instead of pushing them back to the message broker, but I can see why you'd want guaranteed correct delivery. What's the behaviour that you would expect if the callback fails? Negative acknowledgement + requeue, or just no acknowledgement at all? |
I would say safest option by default might be P.S. I started to learn rabbitmq not so long time ago. What I discovered last week that in order to requeue you need to pass |
Have you guys used the |
@aleksarias Yes, because (n-)acknowledging a message ID that has already been ack'd is a channel error under AMQP. Those functions aren't exported, it shouldn't be surprising they don't work... |
@atheriel |
@hampos I'm still not personally convinced of a real use for nacks (since they can't guarantee data safety), and would caution against adopting an architecture that relied on them. Can you give an example of what you're trying to achieve? |
Could you clarify on this point? Usual flow for stream processing is following:
Also client usually counts number of msg retries and in case it exceed some pre-configured number then client sends message to dead letter queue. |
That’s the processing flow I’m used to seeing when working with rabbitmq.
It’s what makes rabbitmq so powerful.
On Mon, Oct 19, 2020 at 2:47 PM Dmitriy Selivanov ***@***.***> wrote:
since they can't guarantee data safety
Could you clarify on this point?
Usual flow for stream processing is following:
- got message
- handle it
- acknowledge at the end after success
- once ack received broker remove message from queue
- if error during handling
- either send nack and re-queue
- or client catch exception in user-code and re-queue
Also client usually counts number of msg retries and in case it exceed
some pre-configured number then client sends message to dead letter queue.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB7TYRACF7HKATMAIXSZKB3SLSCV5ANCNFSM4KOYCC5A>
.
--
…--
Alex L. Arias
Data Engineer
Materials Science & Engineering, B.S.
Cell: +1 305 965 0326
aleksarias@gmail.com
|
Can you explain this a bit more? |
@dselivanov On data safety, RabbitMQ cannot guarantee "exactly once" message delivery, so you must either take extreme care with messages that are redelivered or admit that some messages will be lost. Currently I think this basically comes down to the question, what should an application do when it receives a message where the At the moment, you can be sure that such a message was delivered to a consumer but never passed to any R code, so it's safe to run your callback with side effects (as any real code will have). In fact you can ignore the flag entirely. But if consumers can nack messages after processing, you must consider (and determine) which of the following happened:
You can overcome (1) and (2) by writing your message processing code so that it is idempotent. But For (3), you'd need the current consumer to be sufficiently different from that earlier consumer in order to process it successfully, otherwise you're wasting its time. This is not usually the case, so more likely it will be rejected again and again (until, as in your example, it gets dead-lettered). I don't really know how folks deal with working this out in practice. Instead, we usually handle errors by logging them and sometimes by forwarding the offending messages to an error exchange (which is equivalent to manual dead-lettering), where they will be picked up by a dedicated error service (and, more than likely, logged). Worth reading is this StackOverflow thread; there are several good answers. |
Your next comment explains main cases. Essentially there are 2 edge cases:
Overall requeue increase the chance to eventually handle message and makes system much more robust and reduce the chance to loose data.
That is the whole point of this thread and comments from me and others. As a user of RabbitMQ client I need to be aware that message can be delivered several times and I need to implement handling logic accordingly (side effects ideally should be idempotent). Otherwise we are getting "fire and forget" style message queue which RabbitMQ is not (primarily). |
+1 |
The existing behaviour is basically the same as always having no_ack=TRUE, in that messages are unequivocally acknowledged. However, it is sometimes desirable to distinguish processing which fails from that which succeeds, so callbacks which throw an error will now nack messages instead -- without requeing them. Since nack without requeue is only *semantically* (not operationally) different than acknowledgment, existing workflows are unlikely to be affected. Documentation has been updated to reflect this behaviour. Part of #2.
#10 implements what I believe is enough machinery to accomplish what is discussed in this thread. Here are a few examples: # 1. Messages will be acknowledged *after* the callback runs.
amqp_consume(conn, queue, function(msg) {
message("got msg")
})
# 2. Errors will nack (instead of ack) but not requeue the message.
amqp_consume(conn, queue, function(msg) {
stop("can't handle this")
})
# 3. Errors will instead nack and requeue the message.
amqp_consume(conn, queue, function(msg) {
stop("can't handle this, maybe someone else can")
}, requeue_on_error = TRUE)
# 4. Nack behaviour can be manually controlled by signalling with amqp_nack().
amqp_consume(conn, queue, function(msg) {
if (msg$redelivered) {
message("can't handle this either, dead-letter it")
amqp_nack(requeue = FALSE) # Works like stop().
} else {
stop("can't handle this, maybe someone else can")
}
}, requeue_on_error = TRUE)
|
😍
On Tue, Nov 10, 2020 at 8:46 PM Aaron Jacobs ***@***.***> wrote:
#10 <#10> implements what I
believe is enough machinery to accomplish what is discussed in this thread.
Here are a few examples:
# 1. Messages will be acknowledged *after* the callback runs.
amqp_consume(conn, queue, function(msg) {
message("got msg")
})
# 2. Errors will nack (instead of ack) but not requeue the message.
amqp_consume(conn, queue, function(msg) {
stop("can't handle this")
})
# 3. Errors will instead nack and requeue the message.
amqp_consume(conn, queue, function(msg) {
stop("can't handle this, maybe someone else can")
}, requeue_on_error = TRUE)
# 4. Nack behaviour can be manually controlled by signalling with amqp_nack().
amqp_consume(conn, queue, function(msg) {
if (msg$redelivered) {
message("can't handle this either, dead-letter it")
amqp_nack(requeue = FALSE) # Works like stop().
} else {
stop("can't handle this, maybe someone else can")
}
}, requeue_on_error = TRUE)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB7TYRHI6PSBWD3ZC2TW4YDSPHUFTANCNFSM4KOYCC5A>
.
--
…--
Alex L. Arias
Data Engineer
Materials Science & Engineering, B.S.
Cell: +1 305 965 0326
aleksarias@gmail.com
|
Hi @atheriel. Thanks for your great work on rabbitMQ client.
I see that client sends acknowledgement before callback is executed and regardless the callback status. Shouldn't we send it only if callback haven't thrown an error? Otherwise it becomes a situation that message is not properly consumed and nobody notice that. So essentially message is lost for a system.
The text was updated successfully, but these errors were encountered: