Hi Alex,<div><br></div><div><br></div><div>Firstly, thank you very much for your answer. You've really helped me.</div><div><div>As you suggested we'll update RabbitMQ to version 2.2.0 as soon as possible.</div><div>
It is great you are introducing publisher confirms in next release because it will offer more fine control to message publishing.</div></div><div><br></div><div><br></div><div>Regarding transfer responsibility I have one more doubt.</div>
<div>As you said, "TxCommit will succeed if messages are lost during routing (due to non-existing queues)", </div><div>so does it mean that TxCommit launches an exception when it fails?</div><div><br></div><div>
In this case in my code I should handle unexpected exceptions (txSelect, basic.publish, txCommit) and also basic.return in cause immediate and/or mandatory message can't be delivered, right?</div><div> </div><div><br>
</div><div><br></div><div>Regards,</div><div><br></div><div>Alfonso</div><div><br></div><div><br></div><div><br><br><div class="gmail_quote">
2011/1/27 Alexandru Scvorţov <span dir="ltr"><<a href="mailto:alexandru@rabbitmq.com" target="_blank">alexandru@rabbitmq.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Alfonso,<br>
<div><br>
> I've been googling a lot and some people suggested using this schema:<br>
><br>
> ch.TxSelect()<br>
> ch.BasicPublish(.....)<br>
> ch.TxCommit()<br>
</div>...<br>
<div>> Reading the API user guide I've found that this is called "transfer<br>
> responsibility".<br>
<br>
</div>That's correct. The only way right now to transfer responsibility for<br>
a message to the broker is using transactions.<br>
<br>
That said, I don't think it's exactly what you want. The TxCommit will<br>
succeed if messages are lost during routing (due to non-existing<br>
queues).<br>
<div><br>
<br>
> My question is:<br>
><br>
> Being TxCommit a void function I tested this block of code using a<br>
> non-existing routing key and I didn't get any exception.<br>
> Since safe publishing would be highly desiderable non routed messages should<br>
> be detected because the application ACKs the messages of "events queue"<br>
> when after evaluating its content has successfully sent another message to<br>
> the "results queue" (currently if a a routing key is not being routed to a<br>
> queue the messages are silently dropped and I have no way to detect the<br>
> failure so the application ACKs the messages from "events queue")<br>
><br>
> Please, can someone tell me how I can't get that "CommitOK" responses?<br>
<br>
</div>As far as I know, there's no way cause the broker to throw an exception<br>
for unroutable messages.<br>
<br>
What you could do instead is this:<br>
- as you've suggested, publish with mandatory, immediate, and<br>
persistent set;<br>
- do publishes to persistent queues;<br>
- wrap publishes in that tx code;<br>
- have the publisher watch for basic.returns and handle somehow lost<br>
messages (maybe rollback the transaction, republish to a different<br>
and commit).<br>
<br>
The message flags and the transactions should ensure that the broker<br>
either save the messages to disk or send it to a consumer. The<br>
ReturnHandler should allow you to republish or somehow handle lost<br>
messages.<br>
<br>
Basic.publish/basic.return aren't synchronous out of the box and aren't<br>
meant to be used like that. For unroutable messages, the broker sends<br>
the basic.return immediately after processing the basic.publish, so if<br>
you publish to a non-existent queue, you should expect the basic.return<br>
soonish; you could use this to make publishes/returns somewhat<br>
synchronous, but I wouldn't recommend it.<br>
<br>
BTW, the AMQP spec says you shouldn't rely on the broker's behaviour<br>
when publishing mandatory/immediate messages inside transactions, but I<br>
think there are any pitfalls doing this with rabbit.<br>
<br>
<br>
As you may have guessed by now, the scenario you described isn't handled<br>
very nicely by AMQP. We're introducing publisher confirms to remedy<br>
this. The code's on default now, and should be in the next release.<br>
The basic idea is that the broker sends a basic.ack back to the<br>
publisher when it's dealt with a message. In addition, the basic.return<br>
would always be sent before the basic.ack, so the publisher would know<br>
when the message is no longer its responsibility. Of course, this<br>
isn't synchronous, but it is fast, and the logic is a lot simpler than<br>
trying to do the same thing with transactions.<br>
<div><br>
<br>
> PS: I'm using the API version 1.7.2 and RabbitMQ server is the same version.<br>
<br>
</div>You really should upgrade. Since 1.7.2, we've fixed lots of bugs<br>
(including a few serious ones), introduced a new persister (which is<br>
quite relevant if you care about transfer of responsibility) and added some<br>
very nice management and monitoring features (including a web UI).<br>
Publisher confirms are on default now, and should be in the next<br>
release.<br>
<br>
<br>
Hope this helps,<br>
<br>
Cheers,<br>
Alex<br>
<div><div></div><div><br>
On Mon, Jan 24, 2011 at 05:47:17PM +0100, Alfonso Pantoja wrote:<br>
> Hi,<br>
><br>
> I've developed an application that consumes messages from a queue ("events<br>
> queue") and depending on their data<br>
> it publishes (per received message) a message to another queue ("results<br>
> queue")<br>
><br>
> The logic that checks the content of the received messages is publishing<br>
> messages using BasicPublish (with mandatory=2, immediate=false and setting<br>
> deliveryMode=2 to the messages to be sent)<br>
> My concern is that BasicPublish is asynchronous and the only exception I<br>
> can get is when there is no connection to RabbitMQ or the destination<br>
> exchange does not exist.<br>
><br>
> Since the application logic at this point is synchronous I can't use<br>
> BasicReturn in order to use a handler when messages can't be delivered.<br>
><br>
> I've been googling a lot and some people suggested using this schema:<br>
><br>
> ch.TxSelect()<br>
> ch.BasicPublish(.....)<br>
> ch.TxCommit()<br>
><br>
> and also is suggested that "commit-ok" will be returned if the message has<br>
> been published safely to the broker.<br>
><br>
> Reading the API user guide I've found that this is called "transfer<br>
> responsibility".<br>
><br>
> Copy & paste follows:<br>
><br>
> --<br>
> To transfer responsibility for delivery of a message to a broker<br>
> • ensure (ahead of time) that the target queue exists and is durable,<br>
> • select Tx mode using IModel.TxSelect,<br>
> • publish the message with the "mandatory" flag set and DeliveryMode set<br>
> equal to 2, and<br>
> • commit the Tx transaction using IModel.TxCommit.<br>
><br>
> Once a broker replies with CommitOk (i.e. the TxCommit() call returns to the<br>
> caller), it has taken<br>
> responsibility for keeping the message on disk and on the target queue until<br>
> some other application<br>
> retrieves and acknowledges the message.<br>
> A commit is not required after every message: batching of publications may<br>
> be done, depending on the<br>
> precise delivery guarantees the publishing application requires.<br>
> Responsibility can also be placed with an external database, even further<br>
> along the chain - see the section<br>
> on interaction with external resources below<br>
> ---<br>
><br>
> My question is:<br>
><br>
> Being TxCommit a void function I tested this block of code using a<br>
> non-existing routing key and I didn't get any exception.<br>
> Since safe publishing would be highly desiderable non routed messages should<br>
> be detected because the application ACKs the messages of "events queue"<br>
> when after evaluating its content has successfully sent another message to<br>
> the "results queue" (currently if a a routing key is not being routed to a<br>
> queue the messages are silently dropped and I have no way to detect the<br>
> failure so the application ACKs the messages from "events queue")<br>
><br>
> Please, can someone tell me how I can't get that "CommitOK" responses?<br>
><br>
><br>
> Thank you in advance.<br>
><br>
><br>
> Alfonso<br>
><br>
> PS: I'm using the API version 1.7.2 and RabbitMQ server is the same version.<br>
<br>
</div></div>> _______________________________________________<br>
> rabbitmq-discuss mailing list<br>
> <a href="mailto:rabbitmq-discuss@lists.rabbitmq.com" target="_blank">rabbitmq-discuss@lists.rabbitmq.com</a><br>
> <a href="https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss" target="_blank">https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss</a><br>
<br>
</blockquote></div><br></div>