[rabbitmq-discuss] Broadcasting and STOMP (was Re: python stomp examples)

Tony Garnock-Jones tonyg at lshift.net
Tue Sep 9 13:37:13 BST 2008

Hi Joe,

Novak Joe wrote:
>   this 'just worked' and I could see the messages also propagating to
> the bundled ruby listener that ships with the stomp adapter for
> rabbitmq.


>   If both are subscribed to the 'carl' channel, my intuition tells me
> that both should be able to hear each and every message.
>   Why does this not seem to actually be the case?  (sorry if this is a
> really naive question)
>   Is there some additional header I need to send in order to broadcast
> messages, or is broadcasting a horse of a different color?

This is a good question. Here's where STOMP's definition gets weaker,
and where we start to see AMQP's semantics leaking through.

The way AMQP works is that messages are

 - sent by /producers/ to /exchanges/, and from there are
 - forwarded to /queues/ along /bindings/, from which they are
 - distributed round-robin(ish) to /consumers/

As messages pass through an exchange, they are duplicated, and a /copy/
is sent down each activated binding.

In contrast, when messages leave a queue for a consumer, they are not
duplicated. One message, sitting on a queue, is delivered to only one of
the available consumers. Only if that consumer rejects the message
somehow (e.g. by crashing or otherwise disconnecting before it
acknowledges the message) will the message be sent on by the queue to
some other consumer.

With the STOMP adapter, a plain old

  destination: myqueue

will create a new consumer. If there are multiple clients, all
SUBSCRIBEing to the same queue, then there will be multiple consumers
all on the same queue, leading to round-robin delivery to those clients.

In order to get broadcast behaviour, you need to use a feature
(originally contributed by Artur, now present in the trunk) which
exposes a little more of AMQP's semantics through STOMP:

  id: da9d4779-92b9-4cef-86c0-800bdc977f15
  exchange: amq.topic
  routing_key: #

The empty-string used for the "destination" header tells the adapter to
create a private queue for this one subscription, which will last for
the duration of your connection, or until you UNSUBSCRIBE.

The "id" header should be some string unique to the current connection
(!) which names the subscription. I've used a fresh GUID here, but
anything connection-unique is acceptable.

If you omit the "id" header, the current implementation has a wart
meaning you won't be able to issue more than one SUBSCRIBE with an empty
destination string; we could remove that if absolutely required, but in
my view it's all round simplest and best just to require an "id" header.

The "exchange" header tells the adapter to bind the new private queue to
the named exchange. All AMQP brokers come with preconfigured
"amq.direct", "amq.topic" and "amq.fanout" exchanges, with semantics
described by the AMQP specification (section 3.1.3 of
The "routing_key" header is used as described in §3.1.3 to select which
messages are copied into the queue by the exchange.

The STOMP gateway doesn't provide a way of creating a new exchange, yet;
you have to use a real AMQP client (one that can issue
"exchange.declare" commands) for that, currently. Suggestions welcome!

To unsubscribe from a private queue,

  id: da9d4779-92b9-4cef-86c0-800bdc977f15

as usual, supplying the same "id" you supplied to the SUBSCRIBE.

The private queue will be deleted when the UNSUBSCRIBE has completed.

I've just committed
http://hg.rabbitmq.com/rabbitmq-stomp/rev/8972d204473a, which contains
some (ruby!) examples of topic broadcast, private-queue creation, and

 [][][] Tony Garnock-Jones     | Mob: +44 (0)7905 974 211
   [][] LShift Ltd             | Tel: +44 (0)20 7729 7060
 []  [] http://www.lshift.net/ | Email: tonyg at lshift.net

More information about the rabbitmq-discuss mailing list