<br><br><div class="gmail_quote">On Mon, Nov 10, 2008 at 10:24 AM, Ben Hood <span dir="ltr">&lt;<a href="mailto:0x6e6562@gmail.com">0x6e6562@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Edwin,<br>
<br>
On Sun, Nov 9, 2008 at 11:00 PM, Edwin Fine<br>
<div class="Ih2E3d">&lt;<a href="mailto:rabbitmq-discuss_efine@usa.net">rabbitmq-discuss_efine@usa.net</a>&gt; wrote:<br>
</div><div class="Ih2E3d">&gt; Truly, I always felt uncomfortable with using a cast on publish because you<br>
&gt; can&#39;t tell directly if there was a problem. I&#39;d prefer a call.<br>
<br>
</div>Interesting that you should touch on the issue of transfer of<br>
responsibility in this context. I guess the question you need to ask<br>
is if there is a case where you can do a gen_server:cast and either<br>
loose the message full stop or loose the ordering. My initial thought<br>
is that all practical cases, this is not a problem, but I am following<br>
this up with a question on the Erlang list (which you&#39;ve probably seen<br>
already).<br>
<br>
At this point in time I would be reticent to turn this is into a<br>
gen_server:call/3 because cast/2<br>
<br>
a) matches the asynchronous semantics of the publish command;<br>
b) is a lot quicker than a call;<br>
c) it is pending clarification as to whether there are actually<br>
reordering issues.<br>
<br>
Also, even if you use a call, how will you know that the message<br>
hasn&#39;t been binned by the gen_server instance that you invoked<br>
quasi-synchronously?<br>
</blockquote><div><br>Because the call will return an ok?<br>&nbsp;<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
In general if you want to make sure that you are not losing messages,<br>
you should consider using transactions. Or what would be even better<br>
would be to have an application level acknowledgement.<br>
<div class="Ih2E3d"></div></blockquote><div class="Ih2E3d"><br>Application level acknowldgement, meaning that my consumer explicitly sends an application-level acknowledgement message to the producer? Let me hopefully not annoy you by again comparing with WebSphere MQ. When you PUT a message to the queue manager, you get a return code which, if it is a success, means that the queue manager has got your message and it&#39;s all good. No app level acks needed. No transactions needed. With using a cast to send a message to the broker, if the client has a problem with the message (this happened to me recently), the producer has no idea of this. I only found out by seeing errors in my log file. Or at least, I don&#39;t know of a way to find out other than by starting a transaction, which I am loath to do because of performance concerns.<br>
<br>What happened is that I refactored some code and in doing so created a bug that tried to send a record instead of a list in the basic.publish. Yes, my fault, but I would have liked to have known about it at the code level. The message was lost because there apparently was no way to detect this, let alone recover from it (except maybe the txn, which I have not tried).<br>
<br>== 8-Nov-2008::20:08:59 == ERROR -&nbsp; emulator<br>Error in process &lt;0.191.0&gt; on node &#39;xhg_rel@ender&#39; with exit value: {badarg,[{erlang,list_to_binary,[{frame_rec,&lt;&lt;217 bytes&gt;&gt;,1226192940,0,active,ok,0,undefined,0,&lt;&lt;33 bytes&gt;&gt;}]},{rabbit_binary_generator,create_frame,3},{rabbit_binary_generator,build_content_frames,5},{rabbit_binary_generator,build_simple_content_frames... <br>
<br>
<br>
&gt; Maybe this is a hare-brained idea, but can&#39;t the broker just send a<br>
&gt; channel.flow to the producer; the Erlang client just forwards it on to the<br>
&gt; producer in precisely the same way as it sends a basic.receive to a<br>
&gt; consumer? The publishing application would just need to write a handle_info<br>
&gt; for channel.flow just like a consumer does for basic.receive, or have I<br>
&gt; missed the point?<br>
<br>
</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">When you say basic.receive, I assume you mean basic.deliver.<br>
</blockquote><div>Yes, sorry.<br>&nbsp;<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
Have you looked at the test that I wrote for this in the test_util<br>
module - it does pretty much what you describe.<br>
<div class="Ih2E3d"></div></blockquote><div><br>I have looked at the test, but it does not do anything like what I was trying to describe :)<br><br>What I was trying to describe was having a gen_server or gen_fsm that has a clause something like this;<br>
<br>handle_info(#&#39;channel.flow&#39;{active = false}, State) -&gt;<br>&nbsp;&nbsp;&nbsp; {noreply, State#state{channel_flow = false}};<br><br>handle_info(#&#39;channel.flow&#39;{active = true}, State) -&gt;<br>
&nbsp;&nbsp;&nbsp; {noreply, State#state{channel_flow = true}};<br>
<br>When receiving the &quot;down&quot; signal, the producer can then go into an idle state voluntarily. I don&#39;t like the idea of the client silently throwing away producer messages.<br><br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="Ih2E3d"><br>
&gt; I realize that this means that publishing applications can choose to ignore<br>
&gt; channel.flow commands, but that would be shooting themselves in the foot. In<br>
&gt; the 0.8 spec it says &quot;The peer that requests a Channel.Flow method MAY<br>
&gt; disconnect and/or ban a peer that does not respect the request.&quot;, so the<br>
&gt; server could just drop the channel if the publisher ignores it.<br>
<br>
</div>That&#39;s what it will eventually do.<br>
<div class="Ih2E3d"><br>
&gt; Now I am not sure what is meant by a &quot;peer&quot;, if that&#39;s the client itself or<br>
&gt; the application that is using the client. Either way, I believe that the<br>
&gt; Erlang client simply forwarding the channel.flow command to the application<br>
&gt; and requiring it to respond with the ok (and stop sending) is within the<br>
&gt; spirit of the spec, and should (?) be simple to do in the client.<br>
<br>
</div>ATM the client sends the ack back after it has asynchronously notified<br>
the sending application. The registration for this is analogous to the<br>
return listener registration process (in fact it&#39;s copy and paste). If<br>
the flag is set, any invocation of the cast function will silently<br>
discard the message.<br>
</blockquote><div><br>I really don&#39;t like the sound of that. I don&#39;t like silent discards in general.<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
I think that doing it this way round would be cooler than turning the<br>
cast into a call in order to be able to read the state of the channel<br>
flow flag.<br>
</blockquote><div><br>Well, how about what I suggested above? Just let the client pass the channel.flow on to the app. Why not? <br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
The only issue I see is the added complexity involved in the<br>
application - it would have to have a receive loop that matches on the<br>
pause and resume atoms sent to it by the channel process.<br>
</blockquote><div><br>Not if done the way I suggested. Then it just becomes another handle_info clause and state change.<br>&nbsp;<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
Maybe there is a way to build a convenience function for this in lib_amqp?<br>
<font color="#888888"><br>
Ben<br>
<br>
</font></blockquote></div><br>