[rabbitmq-discuss] Flow Control

Ben Hood 0x6e6562 at gmail.com
Mon Nov 10 15:24:56 GMT 2008


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?

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.


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

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

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

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.

Maybe there is a way to build a convenience function for this in lib_amqp?

Ben




More information about the rabbitmq-discuss mailing list