<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">A superlative follow up - thanks for clearing up the details Steve, and for the history lesson (which I for one, found very enlightening)!<div><br></div><div>Cheers,</div><div>Tim&nbsp;<div><br><div><div>On 24 Sep 2013, at 10:57, Steve Powell wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><meta http-equiv="Content-Type" content="text/html charset=windows-1252"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div>(Previous message sent before finalisation -- please ignore it.)</div><div><br></div><div>Sorry to butt in, but I wanted to clarify a few things (about the Java client):</div><div><br></div><div><span style="text-align: left; ">There is&nbsp;</span><i style="text-align: left; ">no</i><span style="text-align: left; ">&nbsp;‘rule’ “you shouldn’t share a channel between threads”. &nbsp;It is (good) advice, though.</span></div><div><span style="text-align: left; "><br></span></div><div><span style="text-align: left; ">It is&nbsp;</span><i style="text-align: left; ">not</i><span style="text-align: left; ">&nbsp;true that “</span><font face="American Typewriter" style="text-align: left; ">basic.deliver</font><span style="text-align: left; ">&nbsp;will be called on the client library’s internal message loop thread”, <font face="American Typewriter">handleDelivery</font> is called on a&nbsp;<font face="American Typewriter">Consumer</font> callback thread.</span></div><div><span style="text-align: left; "><br></span></div><div><span style="text-align: left; ">It is fine to call <font face="American Typewriter">ack</font> from a <font face="American Typewriter">Consumer</font>.<font face="American Typewriter">handleDelivery</font> method, and it is OK to call any other channel method, <i>but</i>&nbsp;it is hard to program multi-thread control of a channel without&nbsp;getting&nbsp;into serious difficulties.</span></div><div><span style="text-align: left; "><br></span></div><div><span style="text-align: left; ">Some channel commands don't wait for a response, and some do. &nbsp;If you are waiting for a response then your&nbsp;application&nbsp;thread is waiting (blocked). If you issue a second command that wants to wait for a response, the Java Client will block the second thread until the response has returned from the first. &nbsp;This is thread-safe, and as designed. &nbsp;However, there is no serialisation of these requests: if many simultaneously issue commands, they may execute in any order. &nbsp;The state of the channel each command sees is therefore not predictable, and so the application threads need to cope with potential failures and reorderings.</span></div><div><span style="text-align: left; "><br></span></div><div><span style="text-align: left; ">Even commands that don't expect a response can interfere with another thread's commands by changing the state of the channel, so it is quite important that the application threads know what each other are doing.</span></div><div><span style="text-align: left; "><br></span></div><div><span style="text-align: left; ">Issuing <font face="American Typewriter">ack</font>s from many threads runs the risk of a double <font face="American Typewriter">ack</font> (<font face="American Typewriter">ack</font>ing&nbsp;the same message twice), which is a protocol error. &nbsp;</span><span style="text-align: left; ">Multi-<font face="American Typewriter">ack</font>s suffer from the same problem.</span></div><div><span style="text-align: left; "><br></span></div>I refer you to the following sections on the Java Client API documentation page (<a href="http://www.rabbitmq.com/api-guide.html">http://www.rabbitmq.com/api-guide.html</a><span style="font-size: 14px; ">):</span><div><h2 class="docHeading" style="font-family: Helvetica, Arial, sans-serif; margin: 20px 0px 0.5em; padding: 0px; color: rgb(255, 102, 0); font-size: 24px; line-height: 18px; text-align: left; background-color: rgb(255, 255, 255); position: static; z-index: auto; "></h2><blockquote type="cite"><h2 class="docHeading" style="font-family: Helvetica, Arial, sans-serif; margin: 20px 0px 0.5em; padding: 0px; color: rgb(255, 102, 0); font-size: 1.7em; line-height: 18px; text-align: left; background-color: rgb(255, 255, 255); position: static; z-index: auto; ">Channel thread-safety</h2></blockquote></div><blockquote type="cite"><p style="clear: left; color: rgb(85, 85, 85); font-family: Verdana, sans-serif; font-size: 13px; line-height: 18px; text-align: left; background-color: rgb(255, 255, 255); position: static; z-index: auto; "><span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>&nbsp;instances are safe for use by multiple threads. Requests into a<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>&nbsp;are serialized, with only one thread being able to run a command on the&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>&nbsp;at a time. Even so, applications should prefer using a&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>&nbsp;per thread instead of sharing the same&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>&nbsp;across multiple threads.</p></blockquote><div>and, in the following section:</div><div></div><blockquote type="cite"><p style="clear: left; color: rgb(85, 85, 85); font-family: Verdana, sans-serif; font-size: 13px; line-height: 18px; text-align: left; background-color: rgb(255, 255, 255); position: static; z-index: auto; ">Callbacks to&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>s are dispatched on a thread separate from the thread managed by the&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Connection</span>. This means that&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>s can safely call blocking methods on the&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Connection</span>&nbsp;or&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>, such as<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">queueDeclare</span>,&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">txCommit</span>,&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">basicCancel</span>&nbsp;or&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">basicPublish</span>.</p><p style="clear: left; color: rgb(85, 85, 85); font-family: Verdana, sans-serif; font-size: 13px; line-height: 18px; text-align: left; background-color: rgb(255, 255, 255); position: static; z-index: auto; ">Each&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>&nbsp;has its own dispatch thread. For the most common use case of one&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>&nbsp;per&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>, this means&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>s do not hold up other&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>s. If you have multiple&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>s per&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>&nbsp;be aware that a long-running&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>&nbsp;may hold up dispatch of callbacks to other&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Consumer</span>s on that&nbsp;<span class="code " style="color: rgb(51, 51, 51); font-family: 'Courier New', Courier, monospace; font-size: small; white-space: nowrap; ">Channel</span>.</p></blockquote><div style="text-align: left; ">If you are interested…. &nbsp;(background info):</div><div style="text-align: left; "><br></div><div style="text-align: left; ">It&nbsp;<i>used to be the case</i>&nbsp;that the consumer callbacks (e.g.&nbsp;<font face="American Typewriter">handleDelivery</font>) executed on the&nbsp;<font face="American Typewriter">Connection</font>&nbsp;thread. (This is no longer true—see below.) This meant it was quite dangerous to issue channel commands in a callback method: &nbsp;the same thread that listened for frames from the server, might block waiting for a response from a channel command. &nbsp;<i>Deadlock.</i></div><div style="text-align: left; "><br></div><div style="text-align: left; ">The&nbsp;<font face="American Typewriter">basic.ack</font>&nbsp;command&nbsp;was alright, because there is no response waited for (and any other command which doesn’t have a protocol response is fine, too). &nbsp;However, many applications tried to issue channel commands (like&nbsp;<font face="American Typewriter">declareQueue</font>&nbsp;or&nbsp;<font face="American Typewriter">createChannel</font>) which&nbsp;<i>did</i>&nbsp;expect responses, so they ran into trouble.</div><div style="text-align: left; "><br></div><div style="text-align: left; ">To obviate this problem, the&nbsp;<font face="American Typewriter">QueueingConsumer</font>&nbsp;was created: this essentially does all the necessary things in the callback to receive the message, puts it in a (communicating, thread-safe) Java queue, and returns. &nbsp;The message can then be obtained from the Java queue by any other thread, including the original application thread. &nbsp;If channel commands are subsequently issued they cannot block the&nbsp;<font face="American Typewriter">Connection</font>&nbsp;thread.</div><div style="text-align: left; "><br></div><div style="text-align: left; ">Issuing channel commands from more than one thread ran the risk of issuing a command requiring a response (a ‘synchronous’ command) while another thread was already waiting for a response. &nbsp;This would be an error (a thread-safety error) because the client cannot cope with overlapping synchronous commands on the same channel. &nbsp;This is prevented: a thread that issues a command expecting a response will block until any outstanding response is received on that channel.</div><div style="text-align: left; "><br></div><div style="text-align: left; ">Although the thread-safety issues are (should be—let’s not get complacent) now all fixed, this solution just made a deadlock on the&nbsp;<font face="American Typewriter">Connection</font>&nbsp;thread more likely if you were trying to code your own <font face="American Typewriter">Consumer</font>.</div><div style="text-align: left; "><div><br></div><div>In RabbitMQ 2.7.0 and 2.7.1, the Java client was changed to take the callback executions off of the&nbsp;<font face="American Typewriter">Connection</font>&nbsp;thread altogether. This was for three reasons. &nbsp;<i>One</i>&nbsp;was to allow channel commands to be issued in&nbsp;<font face="American Typewriter">handleDelivery</font>&nbsp;(<i>et al.</i>), which, by the way, meant that bespoke&nbsp;<font face="American Typewriter">Consumer</font>s were easier to write—<font face="American Typewriter">QueueingConsumer</font>&nbsp;is now not (so) necessary. &nbsp;The&nbsp;<i>second</i>&nbsp;was to recover more gracefully from&nbsp;<font face="American Typewriter">Consumer</font>s that do silly things: throwing exceptions, hanging indefinitely, and so on. &nbsp;And the&nbsp;<i>third</i>&nbsp;was to prevent&nbsp;<font face="American Typewriter">Consumer</font>s on&nbsp;<i>distinct</i>&nbsp;channels from holding each other up. &nbsp;(There is now a pool of threads used to execute&nbsp;<font face="American Typewriter">Consumer</font>&nbsp;callbacks, each channel’s callbacks being executed serially, but distinct channels’ callbacks being allowed to run concurrently.)</div><div><br></div></div><div style="text-align: left; ">It is quite safe to issue an&nbsp;<font face="American Typewriter">ack</font>&nbsp;(or&nbsp;<font face="American Typewriter">nack</font>) from another thread. &nbsp;But you should beware of doing this twice, so multi-threaded applications need to be carefully designed to avoid ‘confusion’ over which thread does what—“channel control fights”.</div><div style="text-align: left; "><br></div><div style="text-align: left; ">Channel commands can be issued from multiple threads if you can ensure that the correct channel protocol is observed. &nbsp;To do this properly requires communication between the threads in the application, which can be non-trivial to get right (I recommend&nbsp;<i>Java Concurrency in Practice</i>, Addison Wesley, Goetz, et al.).</div><div style="text-align: left; "><br></div><div style="text-align: left; ">So, the ‘<i>advice</i>’ is&nbsp;<i>not</i>&nbsp;to share channels between application threads, but it is&nbsp;<i>just advice</i>. &nbsp;It is expected that you might issue (<font face="American Typewriter">n</font>)<font face="American Typewriter">ack</font>s from the&nbsp;<font face="American Typewriter">Consumer</font>&nbsp;<font face="American Typewriter">handleDelivery</font>&nbsp;method, and put other&nbsp;<font face="American Typewriter">Channel</font>&nbsp;method calls there, too. &nbsp;No rules are being ‘broken’.</div><div style="text-align: left; "><br></div><div>
<div style="color: rgb(0, 0, 0); font-variant: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div style="color: rgb(0, 0, 0); font-variant: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div style="color: rgb(0, 0, 0); font-variant: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div style="color: rgb(0, 0, 0); font-variant: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div style="color: rgb(0, 0, 0); font-variant: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; "><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; "><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><span class="Apple-style-span" style="border-spacing: 0px; border-collapse: separate; "><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><span class="Apple-style-span" style="font-family: Georgia; font-size: 12px; font-weight: normal; font-style: normal; ">Steve Powell &nbsp;</span><font class="Apple-style-span" face="Georgia" size="3" style="font-family: Georgia; font-size: medium; font-weight: normal; font-style: normal; "><span class="Apple-style-span" style="font-size: 11px; ">[</span></font><i style="font-family: Georgia; font-size: medium; font-weight: normal; font-style: normal; "><font class="Apple-style-span" face="Georgia" size="3"><span class="Apple-style-span" style="font-size: 11px; ">Cell</span></font></i><font class="Apple-style-span" face="Georgia" size="3" style="font-family: Georgia; font-size: medium; font-weight: normal; font-style: normal; "><span class="Apple-style-span" style="font-size: 11px; ">: +44-7815-838-558</span></font><font class="Apple-style-span" face="Georgia" style="font-family: Georgia; font-weight: normal; font-style: normal; "><span class="Apple-style-span" style="font-size: 11px; ">]<span class="Apple-converted-space">&nbsp;</span></span><span style="font-size: 10px; ">[</span></font><span style="font-size: 10px; "><a href="http://www.rabbitmq.com/">RabbitMQ</a>,<font face="Helvetica"><i>&nbsp;</i></font><a href="http://gopivotal.com/">Pivotal</a>]</span></div><div style="font-family: Georgia; font-size: medium; font-weight: normal; font-style: normal; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><i style="font-size: 12px; line-height: 19.1875px; ">“L’enfer, c’est les autres.”&nbsp;</i><span style="background-color: rgb(255, 255, 255); font-size: 12px; line-height: 19.1875px; ">Sartre</span></div></span></div></span></div></span></div></div></div></div></div>
</div>
<br><div><div>On 23 Sep 2013, at 15:52, Mike Hadlow &lt;<a href="mailto:mike@suteki.co.uk">mike@suteki.co.uk</a>&gt; wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div dir="ltr">Hi Michael, Tim,<div><br></div><div>I've put your comments into a blog post:&nbsp;<a href="http://mikehadlow.blogspot.co.uk/2013/09/rabbitmq-amqp-channel-best-practices.html">http://mikehadlow.blogspot.co.uk/2013/09/rabbitmq-amqp-channel-best-practices.html</a>.</div>
<div><br></div><div>Let me know if there's anything you'd like to add/change/remove.</div><div><br></div><div>Many thanks</div><div>Mike</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Sep 23, 2013 at 12:35 PM, Michael Klishin <span dir="ltr">&lt;<a href="mailto:michael.s.klishin@gmail.com" target="_blank">michael.s.klishin@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="im"><div class="gmail_extra"><br><div class="gmail_quote">2013/9/23 Mike Hadlow <span dir="ltr">&lt;<a href="mailto:mike@suteki.co.uk" target="_blank">mike@suteki.co.uk</a>&gt;</span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

You shouldn't share a channel between multiple threads, but given that an ACK should be sent on the same channel that the delivery is received mean that one _must_ violate this rule?</blockquote></div><br></div></div>
<div class="gmail_extra">

If you run one consumer per thread, use a new channel for every one of them.<br></div><div class="im"><div class="gmail_extra">-- <br>MK<br><br><a href="http://github.com/michaelklishin" target="_blank">http://github.com/michaelklishin</a><br>


<a href="http://twitter.com/michaelklishin" target="_blank">http://twitter.com/michaelklishin</a><br>
</div></div></div>
<br>_______________________________________________<br>
rabbitmq-discuss mailing list<br>
<a href="mailto:rabbitmq-discuss@lists.rabbitmq.com">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>
_______________________________________________<br>rabbitmq-discuss mailing list<br><a href="mailto:rabbitmq-discuss@lists.rabbitmq.com">rabbitmq-discuss@lists.rabbitmq.com</a><br><a href="https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss">https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss</a><br></blockquote></div><br></div>_______________________________________________<br>rabbitmq-discuss mailing list<br><a href="mailto:rabbitmq-discuss@lists.rabbitmq.com">rabbitmq-discuss@lists.rabbitmq.com</a><br>https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss<br></blockquote></div><br></div></div></body></html>