[rabbitmq-discuss] Flow Control

Edwin Fine rabbitmq-discuss_efine at usa.net
Mon Nov 10 16:18:19 GMT 2008

On Mon, Nov 10, 2008 at 10:24 AM, Ben Hood <0x6e6562 at gmail.com> wrote:

> Edwin,
> On Sun, Nov 9, 2008 at 11:00 PM, Edwin Fine
> <rabbitmq-discuss_efine at usa.net> wrote:
> > Truly, I always felt uncomfortable with using a cast on publish because
> you
> > can't tell directly if there was a problem. I'd prefer a call.
> Interesting that you should touch on the issue of transfer of
> responsibility in this context. I guess the question you need to ask
> is if there is a case where you can do a gen_server:cast and either
> loose the message full stop or loose the ordering. My initial thought
> is that all practical cases, this is not a problem, but I am following
> this up with a question on the Erlang list (which you've probably seen
> already).
> At this point in time I would be reticent to turn this is into a
> gen_server:call/3 because cast/2
> a) matches the asynchronous semantics of the publish command;
> b) is a lot quicker than a call;
> c) it is pending clarification as to whether there are actually
> reordering issues.
> Also, even if you use a call, how will you know that the message
> hasn't been binned by the gen_server instance that you invoked
> quasi-synchronously?

Because the call will return an ok?

> In general if you want to make sure that you are not losing messages,
> you should consider using transactions. Or what would be even better
> would be to have an application level acknowledgement.

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'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't know of a
way to find out other than by starting a transaction, which I am loath to do
because of performance concerns.

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).

== 8-Nov-2008::20:08:59 == ERROR -  emulator
Error in process <0.191.0> on node 'xhg_rel at ender' with exit value:

> Maybe this is a hare-brained idea, but can't the broker just send a
> channel.flow to the producer; the Erlang client just forwards it on to the
> producer in precisely the same way as it sends a basic.receive to a
> consumer? The publishing application would just need to write a
> for channel.flow just like a consumer does for basic.receive, or have I
> missed the point?

When you say basic.receive, I assume you mean basic.deliver.
Yes, sorry.

> Have you looked at the test that I wrote for this in the test_util
> module - it does pretty much what you describe.

I have looked at the test, but it does not do anything like what I was
trying to describe :)

What I was trying to describe was having a gen_server or gen_fsm that has a
clause something like this;

handle_info(#'channel.flow'{active = false}, State) ->
    {noreply, State#state{channel_flow = false}};

handle_info(#'channel.flow'{active = true}, State) ->
    {noreply, State#state{channel_flow = true}};

When receiving the "down" signal, the producer can then go into an idle
state voluntarily. I don't like the idea of the client silently throwing
away producer messages.

> > I realize that this means that publishing applications can choose to
> ignore
> > channel.flow commands, but that would be shooting themselves in the foot.
> In
> > the 0.8 spec it says "The peer that requests a Channel.Flow method MAY
> > disconnect and/or ban a peer that does not respect the request.", so the
> > server could just drop the channel if the publisher ignores it.
> That's what it will eventually do.
> > Now I am not sure what is meant by a "peer", if that's the client itself
> or
> > the application that is using the client. Either way, I believe that the
> > Erlang client simply forwarding the channel.flow command to the
> application
> > and requiring it to respond with the ok (and stop sending) is within the
> > spirit of the spec, and should (?) be simple to do in the client.
> ATM the client sends the ack back after it has asynchronously notified
> the sending application. The registration for this is analogous to the
> return listener registration process (in fact it's copy and paste). If
> the flag is set, any invocation of the cast function will silently
> discard the message.

I really don't like the sound of that. I don't like silent discards in

> I think that doing it this way round would be cooler than turning the
> cast into a call in order to be able to read the state of the channel
> flow flag.

Well, how about what I suggested above? Just let the client pass the
channel.flow on to the app. Why not?

> The only issue I see is the added complexity involved in the
> application - it would have to have a receive loop that matches on the
> pause and resume atoms sent to it by the channel process.

Not if done the way I suggested. Then it just becomes another handle_info
clause and state change.

> Maybe there is a way to build a convenience function for this in lib_amqp?
> Ben
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/attachments/20081110/c51b5e05/attachment.htm 

More information about the rabbitmq-discuss mailing list