| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| Architecture |
| --> |
| <html lang="en"> |
| <head> |
| <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/> |
| <meta content="ActiveMQ's next generation of messaging" name="description"/> |
| <meta content="messaging,stomp,jms,activemq,apollo" name="keywords"/> |
| <meta content="Apollo" name="author"/> |
| <script src="../scripts/jquery.js"></script> |
| <link type="text/css" rel="stylesheet" href="../styles/impact/css/pygmentize.css"/> |
| <link type="text/css" rel="stylesheet" href="../styles/impact/css/site.css"/> |
| <title></title> |
| </head> |
| <body> |
| <div id="navigation"> |
| <div class="wrapper"> |
| <ul> |
| <li><a href="../index.html">Apollo 1.7.1</a></li> |
| <li><a href="../community/developers.html">Developers</a></li> |
| <li><a href="../community/index.html">Community</a></li> |
| <li><a href="../download.html">Download</a></li> |
| </ul> <div></div> |
| </div> |
| </div> |
| <div id="content"> |
| <div class="wrapper"> |
| <h1 id = "Apollo_1_7_1_STOMP_Protocol_Manual">Apollo 1.7.1 STOMP Protocol Manual</h1> |
| |
| <p><div class="toc"><ul style="list-style:none;"> |
| <li><a href="#Using_the_STOMP_Protocol">Using the STOMP Protocol</a></li> |
| <li><ul style="list-style:none;"> |
| <li><a href="#Stomp_Protocol_Options">Stomp Protocol Options</a></li> |
| <li><a href="#Client_Libraries">Client Libraries</a></li> |
| <li><a href="#Connecting">Connecting</a></li> |
| <li><a href="#Destination_Types">Destination Types</a></li> |
| <li><a href="#Topic_Retained_Messages">Topic Retained Messages</a></li> |
| <li><a href="#Reliable_Messaging">Reliable Messaging</a></li> |
| <li><a href="#Message_Expiration">Message Expiration</a></li> |
| <li><a href="#Subscription_Flow_Control">Subscription Flow Control</a></li> |
| <li><a href="#Topic_Durable_Subscriptions">Topic Durable Subscriptions</a></li> |
| <li><a href="#Browsing_Subscriptions">Browsing Subscriptions</a></li> |
| <li><a href="#Queue_Message_Sequences">Queue Message Sequences</a></li> |
| <li><a href="#Using_Queue_Browsers_to_Implement_Durable_Topic_Subscriptions">Using Queue Browsers to Implement Durable Topic Subscriptions</a></li> |
| <li><a href="#Exclusive_Subscriptions">Exclusive Subscriptions</a></li> |
| <li><a href="#Message_Groups">Message Groups</a></li> |
| <li><a href="#Temporary_Destinations">Temporary Destinations</a></li> |
| <li><a href="#Destination_Wildcards">Destination Wildcards</a></li> |
| <li><a href="#Composite_Destinations">Composite Destinations</a></li> |
| <li><a href="#Message_Selectors">Message Selectors</a></li> |
| <li><a href="#Destination_Name_Restrictions">Destination Name Restrictions</a></li> |
| </ul></li> |
| </ul></div></p> |
| |
| <h2 id = "Using_the_STOMP_Protocol">Using the STOMP Protocol</h2> |
| |
| <p>Clients can connect to Apollo using the |
| <a href="http://stomp.github.com/">STOMP</a> protocol. STOMP provides an interoperable |
| messaging wire level protocol that allows any STOMP clients can communicate |
| with any STOMP message broker. It aims to provide easy and widespread |
| messaging interoperability among many languages, platforms and brokers.</p> |
| |
| <p>Apollo supports the following versions of the STOMP specification: </p> |
| |
| <ul> |
| <li><a href="http://stomp.github.com/stomp-specification-1.0.html">STOMP 1.0</a></li> |
| <li><a href="http://stomp.github.com/stomp-specification-1.1.html">STOMP 1.1</a></li> |
| <li><a href="http://stomp.github.com/stomp-specification-1.2.html">STOMP 1.2</a></li> |
| </ul> |
| |
| <p>The specification is short and simple to read, it is highly recommend that users |
| to get familiar with it before using one of the many available client libraries.</p> |
| |
| <h3 id = "Stomp_Protocol_Options">Stomp Protocol Options</h3> |
| |
| <p>You can use the <code>stomp</code> configuration element within the <code>connector</code> element |
| in the <code>apollo.xml</code> configuration file to change the default settings used |
| in the STOMP protocol implementation. The <code>stomp</code> element supports the |
| following configuration attributes:</p> |
| |
| <ul> |
| <li><code>buffer_size</code> : How much each producer or subscription will buffer between |
| the client and the broker. If not set, it will be auto tuned between <code>640k</code> |
| and <code>20k</code> depending on the number of connections open on the broker.</li> |
| <li><code>add_user_header</code> : Name of the header which will be added to every received |
| message received. The value of the header will be set to the id of user that |
| sent the message. Not set by default.</li> |
| <li><code>add_timestamp_header</code> : Name of the header which will be added to every received |
| message received. The value of the header will be set to the time the message |
| was received. The time will be represented as the number of milliseconds elapsed |
| since the UNIX epoch in GMT. Not set by default.</li> |
| <li><code>add_redeliveries_header</code> : Name of the header which will be added to messages |
| sent to consumers if the messages has been redelivered. The value of the header |
| will be set to the number of times the message has been redeliverd. Not set |
| by default.</li> |
| <li><code>max_header_length</code> : The maximum allowed length of a STOMP header. Defaults |
| to <code>10k</code>.</li> |
| <li><code>max_headers</code> : The maximum number of allowed headers in a frame. Defaults |
| to 1000.</li> |
| <li><code>max_data_length</code> : The maximum size of the body portion of a STOMP frame. <br/> |
| Defaults to <code>100M</code>.</li> |
| <li><code>die_delay</code> : The amount of time to delay in milliseconds after an <code>ERROR</code> |
| message is sent to the client and the socket is closed.</li> |
| </ul> |
| |
| <p>The stomp configuration element can also be used to control how the destination |
| headers are parsed and interpreted. The supported attributes are:</p> |
| |
| <ul> |
| <li><code>queue_prefix</code> : Defaults to <code>/queue/</code></li> |
| <li><code>topic_prefix</code> : Defaults to <code>/topic/</code></li> |
| <li><code>path_separator</code> : Defaults to <code>.</code></li> |
| <li><code>destination_separator</code> : Defaults to <code>,</code></li> |
| <li><code>any_child_wildcard</code> : Defaults to <code>*</code></li> |
| <li><code>regex_wildcard_start</code> : Defaults to <code>{</code></li> |
| <li><code>regex_wildcard_end</code> : Defaults to <code>}</code></li> |
| <li><code>any_descendant_wildcard</code> : Defaults to <code>**</code></li> |
| </ul> |
| |
| <p>It also supports nested <code>add_user_header</code> elements to more finely control how |
| user headers are added to received STOMP messages. The <code>add_user_header</code> element |
| should contain the name of the header to set on the STOMP message. It also |
| supports the following attributes:</p> |
| |
| <ul> |
| <li><code>separator</code> : If user has multiple principles which match, this separator |
| will be used to delimit them in the header. If not set, then only the first |
| matching principle will be set in the header.</li> |
| <li><code>kind</code> : The principle kind to look for. Defaults to <code>*</code> (matches all |
| principle kinds)</li> |
| </ul> |
| |
| <p>Example:</p> |
| |
| <div class="syntax"><pre name='code' class='brush: xml; gutter: false;'><code> |
| <connector id="tcp" bind="tcp://0.0.0.0:61613"> |
| <stomp max_header_length="10000"> |
| <add_user_header separator=",">user</add_user_header> |
| </stomp> |
| </connector> |
| </code></pre></div> |
| |
| <h3 id = "Client_Libraries">Client Libraries</h3> |
| |
| <p>There are many open source STOMP clients for different platforms and |
| languages. You can find a full listing of available clients at:</p> |
| |
| <ul> |
| <li><a href="http://stomp.github.com/implementations.html#Clients"><code>http://stomp.github.com/implementations.html#Clients</code></a></li> |
| </ul> |
| |
| <p>The Apollo distribution ships with an <code>examples</code> directory |
| where you can find some simple examples of how to use some of those |
| clients to send and receive messages from a broker instance.</p> |
| |
| <p>This section will focus on clarifying the parts of the STOMP specification |
| which allow servers to choose their behavior and to describe how to access |
| Apollo specific features.</p> |
| |
| <h3 id = "Connecting">Connecting</h3> |
| |
| <p>The default broker configuration secures access to the broker so that only |
| the <code>admin</code> user can connect. The default password for the <code>admin</code> user |
| is <code>password</code>.</p> |
| |
| <p>Example STOMP frame to connect to the broker:</p> |
| |
| <pre><code>CONNECT |
| |
| login:admin |
| passcode:password |
| |
| ^@</code></pre> |
| |
| <p>STOMP 1.0 clients don't specify which virtual host they are connecting to so |
| the broker connects those clients to the first virtual host defined in |
| it's configuration. STOMP 1.1 clients must specify a virtual host when they |
| connect. If no configured virtual host <code>host_name</code> matches the client's |
| requested host, the connection is terminated with an ERROR. Therefore, |
| it is critical that the virtual hosts configuration define all the |
| possible host names that clients may connect to host with.</p> |
| |
| <h3 id = "Destination_Types">Destination Types</h3> |
| |
| <p>Apollo supports three types of destinations, queues, topics, and |
| durable subscriptions.</p> |
| |
| <p>The difference between queues and topics is how messages are delivered to |
| consumers. A queue will load balance it's messages over the connected |
| subscribers so that only one subscriber gets a message. Topics replicate |
| every message sent to it to all the connected subscribers. Queues hold |
| on to unconsumed messages even when there are no subscriptions attached, |
| while a topic will drop messages when there are no connected subscriptions.</p> |
| |
| <p>A durable subscription allows you to create a subscription against a topic |
| which will queue messages even after the client disconnects. Clients |
| can reconnect and consume the queued message originating from the topic |
| at a later time.</p> |
| |
| <p>If you want to send or subscribe to a queue, topic, or durable |
| subscription the STOMP destination should be prefixed with <code>/queue/</code>, |
| <code>/topic/</code> or <code>/dsub/</code> respectively.</p> |
| |
| <p>Example STOMP frame sending to a queue:</p> |
| |
| <pre><code>SEND |
| destination:/queue/a |
| |
| hello queue a |
| ^@</code></pre> |
| |
| <h3 id = "Topic_Retained_Messages">Topic Retained Messages</h3> |
| |
| <p>If a message sent to a Topic has the <code>retain:set</code> header, then |
| the message will be 'remembered' by the topic so that if a new |
| subscription arrives, the last retained message is sent |
| to the subscription. For example if you want a topic |
| to remember the last price published you can send a message |
| that looks like:</p> |
| |
| <pre><code>SEND |
| destination:/topic/stock/IBM |
| retain:true |
| |
| 112.12 |
| ^@</code></pre> |
| |
| <p>You can also send a new message with the <code>retain:remove</code> header |
| to have the topic forget about the last retained message.</p> |
| |
| <p>Note: retained messages are not retained between broker restarts.</p> |
| |
| <h3 id = "Reliable_Messaging">Reliable Messaging</h3> |
| |
| <p>Apollo supports reliable messaging by allowing messages to be |
| persisted so that they can be recovered if there is failure which kills |
| the broker. Processing persistent messages has orders of magnitude more |
| overhead than non-persistent variety. You should only use it if your |
| application really needs it.</p> |
| |
| <p>To have a message be persistent, the sender must add the <code>persistent:true</code> |
| header to the <code>SEND</code> STOMP frame. Furthermore, if you are not sending the |
| message in a transaction, it is recommend that you also add a <code>receipt</code> |
| header. Once the broker responds with a <code>RECEIPT</code> frame correlated to |
| the send, you are guaranteed the broker will not drop the message even if |
| a failure occurs.</p> |
| |
| <p>Example:</p> |
| |
| <pre><code>SEND |
| destination:/queue/a |
| receipt:001 |
| |
| hello queue a |
| ^@</code></pre> |
| |
| <p>The client should not consider the send to have succeeded until he receives |
| the correlated <code>RECEIPT</code> frame from the server. Example:</p> |
| |
| <pre><code>RECEIPT |
| receipt-id:001 |
| |
| ^@</code></pre> |
| |
| <p>It is important to note that to do reliable messaging, your system will |
| be prone to receive duplicate messages. For example, if your sending |
| application dies before it receives the <code>RECEIPT</code> frame, then when it starts |
| up again will probably try to send the same message again which may |
| cause a duplicate message to get placed on the broker.</p> |
| |
| <p>You should only use subscribers which use the <code>client</code> or <code>client-individual</code> |
| ack mode to consume reliable messages. Any messages on a queue delivered to a |
| client which have not been acked when the client disconnects will get |
| redelivered to another subscribed client.</p> |
| |
| <h3 id = "Message_Expiration">Message Expiration</h3> |
| |
| <p>Apollo supports expiring old messages. Unconsumed expired messages |
| are automatically removed from the queue. There's two way to specify |
| when the message will be expired. Y</p> |
| |
| <p>The first way to configure the expiration is by setting the <code>expires</code> message |
| header. The expiration time must be specified as the number of milliseconds |
| since the Unix epoch.</p> |
| |
| <p>Example:</p> |
| |
| <pre><code>SEND |
| destination:/queue/a |
| expires:1308690148000 |
| |
| this message will expire on Tue Jun 21 17:02:28 EDT 2011 |
| ^@</code></pre> |
| |
| <p>The first way to configure the expiration is by setting the <code>ttl</code> message |
| header. The ttl will be intereted to mean the number of milliseconds from |
| when the server receives the message. The broker will add an <code>expires</code> |
| header to the message on your behalf.</p> |
| |
| <p>Example:</p> |
| |
| <pre><code>SEND |
| destination:/queue/a |
| ttl:2000 |
| |
| This message will expire in 2 seconds. |
| ^@</code></pre> |
| |
| <h3 id = "Subscription_Flow_Control">Subscription Flow Control</h3> |
| |
| <p>You can add a <code>credit</code> header to the <code>SUBSCRIBE</code> frame to control the |
| flow of messages delivered to the client. Each subscription maintains 2 |
| credit windows which allows you to control the flow of messages either based |
| on number of messages sent or total number of content bytes delivered to the |
| client. The content bytes are the body of the frame which is usually also |
| set on the <code>content-length</code> header. If either of the two credit windows have |
| a positive value, the server will deliver messages to the client.</p> |
| |
| <p>The <code>credit</code> header value is expected to use the |
| <code>count[,size]</code> syntax where:</p> |
| |
| <ul> |
| <li>count: initial setting of the credit window tracking the remaining number |
| of messages that can be sent. Must be specified.</li> |
| <li>size: initial setting of the credit window tracking the remaining number |
| of content bytes that can be sent. Defaults to the receive buffer size of |
| the TCP socket which is typically 65536 bytes.</li> |
| </ul> |
| |
| <p>If the <code>credit</code> header is not specified it has the same effect |
| as if it had been set to <code>credit:655360,655360</code>. This setting allows the broker |
| to optimally stream many small messages to the client or without overloading |
| the clients processing buffers.</p> |
| |
| <p>As messages are sent from the server to the client, the credit windows are |
| reduced by the corresponding amount. When the client send <code>ACK</code> frames to the |
| server, the credit windows are incremented by the number of messages and content |
| sizes corresponding to the messages that were acknowledged.</p> |
| |
| <p>Example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| destination:/queue/foo |
| credit:5,0 |
| |
| ^@</code></pre> |
| |
| <p>The above example would cause the subscription to only receive at most 5 |
| messages if the client is not sending any <code>ACK</code> messages back to the server.</p> |
| |
| <p>If you need to receive more messages without acknowledging them than the |
| size of the credit window, you should use transactions and transactionally |
| <code>ACK</code> messages as they are received. A transactional ACK increases the |
| credit window without actually consuming the messages. If the transaction |
| is aborted subsequent acknowledgements of a previously acknowledged message |
| does not increase the credit window.</p> |
| |
| <!-- The following feature seems complicated and not really that useful.--> |
| |
| <!-- Commenting out as it may get removed. --> |
| |
| <!-- |
| |
| If the `auto` option is set to `false`, then the credit windows are only |
| increased when the server receives `ACK` frames which contain a `credit` |
| header. The header value is expected to use the `count[,size]` syntax. If |
| `size` is specified, it defaults to 0. |
| |
| Example: |
| |
| SUBSCRIBE |
| id:mysub |
| destination:/queue/foo |
| credit:1,0,false |
| |
| ^@ |
| ACK |
| id:mysub |
| message-id:id-52321 |
| credit:1,1204 |
| |
| ^@ |
| |
| You can also use the `ACK` frame to increase the credit windows sizes |
| without needing to acknowledge as message. To do this, don't include the |
| `message-id` header in the `ACK` frame. Example: |
| |
| ACK |
| id:mysub |
| credit:3 |
| |
| ^@ |
| --> |
| |
| <h3 id = "Topic_Durable_Subscriptions">Topic Durable Subscriptions</h3> |
| |
| <p>A durable subscription is a queue which is subscribed to a topic so that even |
| if the client which created the durable subscription is not online, he can |
| still get a copy of all the messages sent to the topic when he comes back |
| online. Multiple clients can subscribe to the same durable subscription and |
| since it's backed by a queue, those subscribers will have the topic's messages |
| load balanced across them.</p> |
| |
| <p>To create or reattach to a a durable subscription with STOMP, you uniquely |
| name the durable subscription using the <code>id</code> header on the <code>SUBSCRIBE</code> frame |
| and also adding a <code>persistent:true</code> header. Example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| persistent:true |
| destination:/topic/foo |
| |
| ^@</code></pre> |
| |
| <p>A standard <code>UNSUBSCRIBE</code> frame does not destroy the durable subscription, it |
| only disconnects the client from the durable subscription. To destroy a |
| durable subscription, you must once again add <code>persistent:true</code> header to the |
| <code>UNSUBSCRIBE</code> frame. Example:</p> |
| |
| <pre><code>UNSUBSCRIBE |
| id:mysub |
| persistent:true |
| |
| ^@</code></pre> |
| |
| <p>If the durable subscription already exists you can address it directly using |
| <code>/dsub/</code> prefix on the <code>destination</code> header. For example, send a message to |
| the previously created <code>mysub</code> durable subscription, you send the following |
| STOMP frame:</p> |
| |
| <pre><code>SEND |
| destination:/dsub/mysub |
| |
| hello durable sub! |
| ^@</code></pre> |
| |
| <p>Similarly, you can also subscribe to the subscription in the same way:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:0 |
| destination:/dsub/mysub |
| |
| ^@</code></pre> |
| |
| <p>Unlike typical STOMP subscriptions id's which are local to the STOMP client's |
| connection, the durable subscription id's are global across a virtual host. If |
| two different connections use the same durable subscription id, then messages |
| from the subscription will get load balanced across the two connections. If |
| the second connection uses a different <code>destination</code> or <code>selector</code> header, |
| then updates the original subscription, and the original connection will |
| subsequently only receive messages matching the updated destination or |
| selector.</p> |
| |
| <h3 id = "Browsing_Subscriptions">Browsing Subscriptions</h3> |
| |
| <p>A normal subscription on a queue will consume messages so that no other |
| subscription will get a copy of the message. If you want to browse all the |
| messages on a queue in a non-destructive fashion, you can create browsing |
| subscription. Browsing subscriptions also works with durable subscriptions |
| since they are backed by a queue. To make a a browsing subscription, just add |
| the <code>browser:true</code> header to the <code>SUBSCRIBE</code> frame. For example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| browser:true |
| destination:/queue/foo |
| |
| ^@</code></pre> |
| |
| <p>Once the broker sends a browsing subscription the last message in the queue, |
| it will send the subscription a special “end of browse” message to indicate |
| browsing has completed and that the subscription should not expect any more |
| messages. The “end of browse” message will have a <code>browser:end</code> header set. |
| Example:</p> |
| |
| <pre><code>MESSAGE |
| subscription:mysub |
| destination: |
| message-id: |
| browser:end |
| |
| ^@</code></pre> |
| |
| <p>If you want the browsing subscription to remain active and continue to listen |
| for message once the last message on the queue is reached, you should add the |
| <code>browser-end:false</code> header to the <code>SUBSCRIBE</code> frame. When the |
| <code>browser-end:false</code> header is added the subscription will not be sent the “end |
| of browse” message previously described.</p> |
| |
| <h3 id = "Queue_Message_Sequences">Queue Message Sequences</h3> |
| |
| <p>As messages are added to a queue in a broker, they are assigned an |
| incrementing sequence number. Messages delivered to subscribers can be updated |
| to include the sequence number if the <code>include-seq</code> header is added to the |
| <code>SUBSCRIBE</code> frame. This header should be set to a header name which will be |
| added messages delivered to hold value of the sequence number.</p> |
| |
| <p>Example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| destination:/queue/foo |
| include-seq:seq |
| |
| ^@</code></pre> |
| |
| <p>Then you can expect to receive messages like:</p> |
| |
| <pre><code>MESSAGE |
| subscription:mysub |
| destination:/queue/foo |
| seq:1 |
| |
| Hello |
| ^@ |
| MESSAGE |
| subscription:mysub |
| destination:/queue/foo |
| seq:2 |
| |
| World |
| ^@</code></pre> |
| |
| <p>Furthermore, you can configure the <code>SUBSCRIBE</code> frame so that the subscription |
| only receives messages that have a sequence id that is equal to or greater |
| than a requested value by using the <code>from-seq</code> header. Example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| destination:/queue/foo |
| from-seq:10 |
| |
| ^@</code></pre> |
| |
| <p>If the <code>from-seq</code> is set to <code>-1</code>, then the subscription will receive messages |
| from the tail of the queue. In other words, it will only receive new messages |
| sent to the queue.</p> |
| |
| <p>Note: You can only use the <code>from-seq</code> header with normal destinations. If you |
| attempt to use it with a wildcard or composite destination then the connection |
| will be closed due to invalid usage.</p> |
| |
| <h3 id = "Using_Queue_Browsers_to_Implement_Durable_Topic_Subscriptions">Using Queue Browsers to Implement Durable Topic Subscriptions</h3> |
| |
| <p>You can use queue browsers with consumer side message sequence tracking to |
| achieve the same semantics as durable topics subscriptions but with a better |
| performance profile. Since browsers do not delete messages from a queue, when |
| you use multiple browsers against one queue you get the same broadcast effects |
| that a topic provides.</p> |
| |
| <p>In this approach the subscribing application keeps track of the last sequence |
| number processed from the subscription. The sequence number is typically |
| stored as part of the unit of work which is processing the message. The |
| subscription can use the default auto acknowledge mode but still get 'once and |
| only once' delivery guarantees since:</p> |
| |
| <ul> |
| <li>consuming application records the last message sequence that |
| was processed</li> |
| <li>message are not deleted when delivered to the subscriber</li> |
| <li>on restart consuming application continues receiving from the queue |
| for the last sequence that it received.</li> |
| </ul> |
| |
| <p>The <code>SUBSCRIBE</code> frame used to create the browser should add the <code>include-seq</code>, |
| <code>from-seq</code>, and <code>browser-end</code> headers so that they can resume receiving |
| messages from the queue from the last known sequence. If you are starting a |
| new consumer that does not have a last processed sequence number, you can |
| either set <code>from-seq</code> to:</p> |
| |
| <ul> |
| <li><code>0</code> to start receiving at the head of the queue which sends |
| the subscription a copy of all the messages that are currently |
| queued.</li> |
| <li><code>-1</code> to start receiving at the tail of the queue which to skips |
| over all the message that exist in the queue so that the subscription |
| only receives new messages.</li> |
| </ul> |
| |
| <p>Example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| destination:/queue/foo |
| browser:true |
| browser-end:false |
| include-seq:seq |
| from-seq:0 |
| |
| ^@</code></pre> |
| |
| <p>Since this approach does not consume the messages from the queue, you should |
| either:</p> |
| |
| <ul> |
| <li>Send messages to the queue with an expiration time so that they are |
| automatically delete once the expiration time is reached.</li> |
| <li>Periodically run a normal consumer application which can cursor the queue |
| and delete messages are are deemed no longer needed.</li> |
| </ul> |
| |
| <h3 id = "Exclusive_Subscriptions">Exclusive Subscriptions</h3> |
| |
| <p>We maintain the order of messages in queues and dispatch them to |
| subscriptions in order. However if you have multiple subscriptions consuming |
| from the same queue, you will loose the guarantee of processing the messages |
| in order; since the messages may be processed concurrently on different |
| subscribers.</p> |
| |
| <p>Sometimes it is important to guarantee the order in which messages are |
| processed. e.g. you don't want to process the update to an order until an |
| insert has been done; or to go backwards in time, overwriting an newer update |
| of an order with an older one etc.</p> |
| |
| <p>So what folks have to do in clusters is often to only run one consumer |
| process in a cluster to avoid loosing the ordering. The problem with this is |
| that if that process goes down, no one is processing the queue any more, |
| which can be problem.</p> |
| |
| <p>Apollo supports exclusive subscriptions which avoids the end user |
| having to restrict himself to only running one process. The broker will pick |
| a single subscription to get all the messages for a queue to ensure ordering. |
| If that subscription fails, the broker will auto failover and choose another |
| subscription.</p> |
| |
| <p>An exclusive subscription is created by adding a <code>exclusive:true</code> header |
| to the <code>SUBSCRIBE</code> frame. Example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| exclusive:true |
| destination:/queue/foo |
| |
| ^@</code></pre> |
| |
| <h3 id = "Message_Groups">Message Groups</h3> |
| |
| <p>Message Groups are an enhancement to the Exclusive Consumer feature to provide</p> |
| |
| <ul> |
| <li>guaranteed ordering of the processing of related messages across a single queue</li> |
| <li>load balancing of the processing of messages across multiple consumers</li> |
| <li>high availability / auto-failover to other consumers if a JVM goes down</li> |
| </ul> |
| |
| <p>Message Groups are logically like a parallel Exclusive Consumer. Rather |
| than all messages going to a single consumer, the stomp <code>message_group</code> header |
| is used to define which message group the message belongs to. The Message Group |
| feature then ensures that all messages for the same message group will be sent to |
| the currently assigned consumer for the group. The assigned consumer consumer |
| for a message group may change but not before all messages sent to the previous |
| consumer are acked or if the consumer is disconnected.</p> |
| |
| <p>Another way of explaining Message Groups is that it provides sticky load balancing |
| of messages across consumers; where the message group value is kinda like a HTTP |
| session ID or cookie value and the message broker is acting like a HTTP load balancer.</p> |
| |
| <p>Here is an example message with the message group set:</p> |
| |
| <pre><code>MESSAGE |
| destination:/queue/PO.REQUEST |
| message_group:hiram |
| |
| PO145 |
| ^@</code></pre> |
| |
| <p>The broker uses consistent hashing to map message groups to consumers. When you add another |
| subscription to a queue, the broker will first wait for messages sent to previous subscriptions |
| to be processed and then the broker rebalances the message groups across the attached consumers.</p> |
| |
| <h3 id = "Temporary_Destinations">Temporary Destinations</h3> |
| |
| <p>Temporary destinations are typically used to receive response messages in |
| a request/response messaging exchange. A temporary destination can only |
| be consumed by a subscription created on the connection which is associated |
| with the temporary destination. Once the connection is closed, all associated |
| temporary destinations are removed. Temporary destinations are prefixed with:</p> |
| |
| <ul> |
| <li><code>/temp-queue/</code> - For temporary queues. Has the same delivery semantics as queues.</li> |
| <li><code>/temp-topic/</code> - For temporary topics. It has the same delivery semantics of topics.</li> |
| </ul> |
| |
| <p>In a request/response scenario, you would first subscribe to the temporary topic:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:mysub |
| destination:/temp-queue/example |
| |
| ^@</code></pre> |
| |
| <p>Then you would send a request with the reply-to header set to the temporary destination. |
| Example:</p> |
| |
| <pre><code>SEND |
| destination:/queue/PO.REQUEST |
| reply-to:/temp-queue/example |
| |
| PO145 |
| ^@</code></pre> |
| |
| <p>The consumer receiving the request will receive a message similar to:</p> |
| |
| <pre><code>MESSAGE |
| subscription:foo |
| reply-to:/queue/temp.default.23.example |
| destination:/queue/PO.REQUEST |
| reply-to:/temp-queue/example |
| |
| PO145</code></pre> |
| |
| <p>Notice that the reply-to` header value is updated from a temporary destination |
| name to normal destination name. The subscription servicing he requests should respond |
| to the updated destination value (<code>/queue/temp.default.23.example</code> in the example above).</p> |
| |
| <p>Temporary destination names actually map to normal queues and topics. They just have |
| a <code>temp.<broker_id>.<connection_id>.</code> prefix. Any destination which starts with |
| <code>temp.</code> has a security policy which only allows the connection which created it |
| to subscribe from it. These destinations are also auto deleted once the connection |
| is closed.</p> |
| |
| <h3 id = "Destination_Wildcards">Destination Wildcards</h3> |
| |
| <p>We support destination wildcards to easily subscribe to multiple destinations |
| with one subscription. This concept has been popular in financial market data |
| for some time as a way of organizing events (such as price changes) into |
| hierarchies and to use wildcards for easy subscription of the range of |
| information you're interested in.</p> |
| |
| <ul> |
| <li><code>.</code> is used to separate names in a path</li> |
| <li><code>*</code> is used to match any name in a path</li> |
| <li><code>{regex}</code> is used to match a path name against a regular expression.</li> |
| <li><code>**</code> is used to recursively match path names</li> |
| </ul> |
| |
| <p>For example imagine you are sending price messages from a stock exchange feed. |
| You might use some kind of destination naming conventions such as:</p> |
| |
| <ul> |
| <li><code>/topic/PRICE.STOCK.NASDAQ.IBM</code> to publish IBM's price on NASDAQ and</li> |
| <li><code>/topic/PRICE.STOCK.NYSE.SUNW</code> to publish Sun's price on the New York Stock Exchange</li> |
| </ul> |
| |
| <p>A subscriber could then use exact destinations to subscribe to exactly the |
| prices it requires. Or it could use wildcards to define hierarchical pattern |
| matches to the destinations to subscribe from.</p> |
| |
| <p>For example using the example above, these subscriptions are possible</p> |
| |
| <ul> |
| <li><code>/topic/PRICE.**</code> : Any price for any product on any exchange</li> |
| <li><code>/topic/PRICE.STOCK.**</code> : Any price for a stock on any exchange</li> |
| <li><code>/topic/PRICE.STOCK.NASDAQ.*</code> : Any stock price on NASDAQ</li> |
| <li><code>/topic/PRICE.STOCK.*.IBM</code> : Any IBM stock price on any exchange</li> |
| <li><code>/topic/PRICE.STOCK.*.I*</code> : Any stock price starting with 'I' on any exchange</li> |
| <li><code>/topic/PRICE.STOCK.*.*{[0-9]}</code> : Any stock price that ends in a digit on any exchange</li> |
| </ul> |
| |
| <p>Destination wildcards can only be used in a SUBSCRIBE frame.</p> |
| |
| <h3 id = "Composite_Destinations">Composite Destinations</h3> |
| |
| <p>You can use composite destinations to send or subscribe to multiple |
| destinations at one time. You use separator of <code>,</code> between destination |
| names. For example, to send one message to 2 queues and 1 topic:</p> |
| |
| <pre><code>SEND |
| destination:/queue/a,/queue/b,/topic/c |
| |
| Composites rock! |
| ^@</code></pre> |
| |
| <h3 id = "Message_Selectors">Message Selectors</h3> |
| |
| <p>Message selectors allow a subscription to only receive a subset of the |
| messages sent to a destination. The selector acts like a filter which |
| is applied against the message properties and only those messages |
| which match pass through to the subscription. </p> |
| |
| <p>Selectors are defined using SQL 92 syntax and typically apply to message |
| headers; whether the standard properties available on a JMS message or custom |
| headers you can add via the JMS code.</p> |
| |
| <p>Here is an example:</p> |
| |
| <pre><code>type = 'car' AND color = 'blue' AND weight > 2500</code></pre> |
| |
| <p>To create a subscription with a message selector, you set the <code>selector</code> |
| header in the STOMP <code>SUBSCRIBE</code> frame to the desired selector. Example:</p> |
| |
| <pre><code>SUBSCRIBE |
| id:sub0 |
| selector:type = 'car' AND color = 'blue' AND weight > 2500 |
| destination:/topic/foo |
| |
| ^@</code></pre> |
| |
| <h3 id = "Destination_Name_Restrictions">Destination Name Restrictions</h3> |
| |
| <p>Destination names are restricted to using the characters <code>a-z</code>, <code>A-Z</code>, <code>0-9</code>, |
| <code>_</code>, <code>-</code> <code>%</code>, <code>~</code>, <code>:</code>, ' ', '(', ')' or <code>.</code> in addition to composite separator <code>,</code> and the wild |
| card <code>*</code>. Any other characters must be UTF-8 and then URL encoded if you wish to |
| preserve their significance.</p> |
| <div></div> |
| </div> |
| </div> |
| </body> |
| </html> |