JBoss.orgCommunity Documentation

Chapter 5. Consuming Messages via Pull

5.1. Auto-Acknowledge
5.1.1. Creating an Auto-Ack Consumer or Subscription
5.1.2. Consuming Messages
5.1.3. Recovering From Network Failures
5.1.4. Recovering From Client or Server Crashes
5.2. Manual Acknowledgement
5.2.1. Creating manually-acknowledged consumers or subscriptions
5.2.2. Consuming and Acknowledging a Message
5.2.3. Recovering From Network Failures
5.2.4. Recovering From Client or Server Crashes
5.3. Blocking Pulls with Accept-Wait
5.4. Clean Up Your Consumers!

There are two different ways to consume messages from a topic or queue. You can wait and have the messaging server push them to you, or you can continuously poll the server yourself to see if messages are available. This chapter discusses the latter. Consuming messages via a pull works almost identically for queues and topics with some minor, but important caveats. To start consuming you must create a consumer resource on the server that is dedicated to your client. Now, this pretty much breaks the stateless principle of REST, but after much prototyping, this is the best way to work most effectively with HornetQ through a REST interface.

You create consumer resources by doing a simple POST to the URL published by the msg-pull-consumers response header if you're interacting with a queue, the msg-pull-subscribers response header if you're interacting with a topic. These headers are provided by the main queue or topic resource discussed in Chapter 3. Doing an empty POST to one of these URLs will create a consumer resource that follows an auto-acknowledge protocol and, if you're interacting with a topic, creates a temporty subscription to the topic. If you want to use the acknowledgement protocol and/or create a durable subscription (topics only), then you must use the form parameters (application/x-www-form-urlencoded) described below.

autoAck

A value of true or false can be given. This defaults to true if you do not pass this parameter.

durable

A value of true or false can be given. This defaults to false if you do not pass this parameter. Only available on topics. This specifies whether you want a durable subscription or not. A durable subscription persists through server restart.

name

This is the name of the durable subscription. If you do not provide this parameter, the name will be automatically generated by the server. Only usable on topics.

selector

This is an optional JMS selector string. The HornetQ REST interface adds HTTP headers to the JMS message for REST produced messages. HTTP headers are prefixed with "http_" and every '-' charactor is converted to a '$'.

idle-timeout

For a topic subscription, idle time in milliseconds in which the consumer connections will be closed if idle.

delete-when-idle

Boolean value, If true, a topic subscription will be deleted (even if it is durable) when an the idle timeout is reached.

This section focuses on the auto-acknowledge protocol for consuming messages via a pull. Here's a list of the response headers and URLs you'll be interested in.

Here is an example of creating an auto-acknowledged queue pull consumer.

Creating an auto-acknowledged consumer for a topic is pretty much the same. Here's an example of creating a durable auto-acknowledged topic pull subscription.

After you have created a consumer resource, you are ready to start pulling messages from the server. Notice that when you created the consumer for either the queue or topic, the response contained a msg-consume-next response header. POST to the URL contained within this header to consume the next message in the queue or topic subscription. A successful POST causes the server to extract a message from the queue or topic subscription, acknowledge it, and return it to the consuming client. If there are no messages in the queue or topic subscription, a 503 (Service Unavailable) HTTP code is returned.

Here's an example of pulling multiple messages from the consumer resource.

  1. Do a POST on the msg-consume-next URL that was returned with the consumer or subscription resource discussed earlier.

    POST /queues/jms.queue.bar/pull-consumers/consume-next-1
    Host: example.com
    
    --- Response ---
    HTTP/1.1 200 Ok
    Content-Type: application/xml
    msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-2
    msg-consumer: http://example.com/queues/jms.queue.bar/pull-consumers/333
    
    <order>...</order>
    

    The POST returns the message consumed from the queue. It also returns a new msg-consume-next link. Use this new link to get the next message. Notice also a msg-consumer response header is returned. This is a URL that points back to the consumer or subscription resource. You will need that to clean up your connection after you are finished using the queue or topic.

  2. The POST returns the message consumed from the queue. It also returns a new msg-consume-next link. Use this new link to get the next message.

    POST /queues/jms.queue.bar/pull-consumers/consume-next-2
    Host: example.com
    
    --- Response ---
    Http/1.1 503 Service Unavailable
    Retry-After: 5
    msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-2
    

    In this case, there are no messages in the queue, so we get a 503 response back. As per the HTTP 1.1 spec, a 503 response may return a Retry-After head specifying the time in seconds that you should retry a post. Also notice, that another new msg-consume-next URL is present. Although it probabley is the same URL you used last post, get in the habit of using URLs returned in response headers as future versions of HornetQ REST might be redirecting you or adding additional data to the URL after timeouts like this.

  3. POST to the URL within the last msg-consume-next to get the next message.

    POST /queues/jms.queue.bar/pull-consumers/consume-next-2
    Host: example.com
    
    --- Response ---
    HTTP/1.1 200 Ok
    Content-Type: application/xml
    msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-3
    
    <order>...</order>

The manual acknowledgement protocol is similar to the auto-ack protocol except there is an additional round trip to the server to tell it that you have received the message and that the server can internally ack the message. Here is a list of the respone headers you will be interested in.

Here is an example of creating an auto-acknowledged queue pull consumer.

Creating an manually-acknowledged consumer for a topic is pretty much the same. Here's an example of creating a durable manually-acknowledged topic pull subscription.

After you have created a consumer resource, you are ready to start pulling messages from the server. Notice that when you created the consumer for either the queue or topic, the response contained a msg-acknowledge-next response header. POST to the URL contained within this header to consume the next message in the queue or topic subscription. If there are no messages in the queue or topic subscription, a 503 (Service Unavailable) HTTP code is returned. A successful POST causes the server to extract a message from the queue or topic subscription and return it to the consuming client. It does not acknowledge the message though. The response will contain the acknowledgement header which you will use to acknowledge the message.

Here's an example of pulling multiple messages from the consumer resource.

  1. Do a POST on the msg-acknowledge-next URL that was returned with the consumer or subscription resource discussed earlier.

    POST /queues/jms.queue.bar/pull-consumers/consume-next-1
    Host: example.com
    
    --- Response ---
    HTTP/1.1 200 Ok
    Content-Type: application/xml
    msg-acknowledgement: http://example.com/queues/jms.queue.bar/pull-consumers/333/acknowledgement/2
    msg-consumer: http://example.com/queues/jms.queue.bar/pull-consumers/333
    
    <order>...</order>
    

    The POST returns the message consumed from the queue. It also returns a msg-acknowledgement link. You will use this new link to acknowledge the message. Notice also a msg-consumer response header is returned. This is a URL that points back to the consumer or subscription resource. You will need that to clean up your connection after you are finished using the queue or topic.

  2. Acknowledge or unacknowledge the message by doing a POST to the URL contained in the msg-acknowledgement header. You must pass an acknowledge form parameter set to true or false depending on whether you want to acknowledge or unacknowledge the message on the server.

    POST /queues/jms.queue.bar/pull-consumers/acknowledgement/2
    Host: example.com
    Content-Type: application/x-www-form-urlencoded
    
    acknowledge=true
    
    --- Response ---
    Http/1.1 200 Ok
    msg-acknowledge-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/acknowledge-next-2
    

    Whether you acknowledge or unacknowledge the message, the response will contain a new msg-acknowledge-next header that you must use to obtain the next message.

Unless your queue or topic has a high rate of message flowing though it, if you use the pull protocol, you're going to be receiving a lot of 503 responses as you continuously pull the server for new messages. To alleviate this problem, the HornetQ REST interface provides the Accept-Wait header. This is a generic HTTP request header that is a hint to the server for how long the client is willing to wait for a response from the server. The value of this header is the time in seconds the client is willing to block for. You would send this request header with your pull requests. Here's an example:

POST /queues/jms.queue.bar/pull-consumers/consume-next-2
Host: example.com
Accept-Wait: 30

--- Response ---
HTTP/1.1 200 Ok
Content-Type: application/xml
msg-consume-next: http://example.com/queues/jms.queue.bar/pull-consumers/333/consume-next-3

<order>...</order>

In this example, we're posting to a msg-consume-next URL and telling the server that we would be willing to block for 30 seconds.

When the client is done with its consumer or topic subscription it should do an HTTP DELETE call on the consumer URL passed back from the Location header or the msg-consumer response header. The server will time out a consumer with the value configured from Chapter 2.3, so you don't have to clean up if you dont' want to, but if you are a good kid, you will clean up your messes. A consumer timeout for durable subscriptions will not delete the underlying durable JMS subscription though, only the server-side consumer resource (and underlying JMS session).