| <div class="wiki-content maincontent"><h2>RESTful Queue</h2> |
| |
| <p>This document is intended to document the ideal RESTful interface to message queues in light of</p> |
| |
| <ul><li><a shape="rect" href="http://tech.groups.yahoo.com/group/rest-discuss/message/8955">the discussion on rest-discuss</a></li><li><a shape="rect" href="http://bitworking.org/projects/atom/draft-ietf-atompub-protocol-17.html">Atom Publishing Protocol</a> (APP)</li><li><a shape="rect" href="http://www.dehora.net/doc/httplr/draft-httplr-01.html">httplr</a></li></ul> |
| |
| |
| <h3>Issues with Queues and REST</h3> |
| |
| <p>One of the main issues with making a truly RESTful API to a message queue is that a message queue is essentially a load balancer, so each consumer of a queue sees essentially a different queue; as only one consumer gets a copy of each message.</p> |
| |
| <p>Also if a consumer goes away, the messages that were associated with that consumer need to be re-assigned to another consumer. So the main tricky part really is the operation for a consumer to find out what messages it may consume.</p> |
| |
| <h3>Queue administration</h3> |
| |
| <p>This section deals with the general browsing and creation/deletion of queues.</p> |
| |
| <h4>Browse available queues</h4> |
| |
| <p>To browse the queues, they are a hierarchial structure usually, so lets browse them like any APP collection</p> |
| |
| <structured-macro ac:macro-id="3fa761d7-8cd8-4f8c-83b8-a2b1668580a4" ac:name="code" ac:schema-version="1"><plain-text-body> |
| GET /queues |
| --------------------> |
| |
| 200 OK |
| Atom Feed with one entry per directory/category/queue |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <h4>Browse a queue's messages</h4> |
| |
| <structured-macro ac:macro-id="1bf2b8f7-f81e-4248-8e19-1e9fd926097a" ac:name="code" ac:schema-version="1"><plain-text-body> |
| GET /queues/uk/products/books/computers |
| --------------------> |
| |
| 200 OK |
| Atom Feed with one entry per pending message |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <p>Note that we could expose the queues as a tree, for example</p> |
| |
| <structured-macro ac:macro-id="9e54d0a4-4970-4724-a2f9-a6f0d29def2d" ac:name="code" ac:schema-version="1"><plain-text-body> |
| GET /queues/uk/products |
| --------------------> |
| |
| 200 OK |
| Atom Feed with one entry per queue in uk.products.* together with any child catgory/directory |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <h4>Creating a queue</h4> |
| |
| <p>Creating a queue is typically idempotent; since really you are just creating a name that folks can post to.</p> |
| |
| <structured-macro ac:macro-id="75a802e6-2ef3-4091-81ed-000610653001" ac:name="code" ac:schema-version="1"><plain-text-body> |
| POST /queues |
| --------------------> |
| |
| 201 OK |
| Location: someUniqueUrlForTheNewQueueToBePostedTo |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <h4>Deleting a queue</h4> |
| |
| <structured-macro ac:macro-id="346b40b2-c328-4458-b4ea-26a176422a1a" ac:name="code" ac:schema-version="1"><plain-text-body> |
| DELETE /queues/foo.bar |
| --------------------> |
| |
| 200 OK |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <h3>Send to queue</h3> |
| |
| <p>Sending to queue is the usual APP-style double request; one to get the unique URI to post to and secondly to do the actual post...</p> |
| |
| <structured-macro ac:macro-id="6f2ef332-dfeb-4e45-9d03-c204a1a7bd72" ac:name="code" ac:schema-version="1"><plain-text-body> |
| POST /queues/foo.bar |
| --------------------> |
| |
| 201 OK |
| Location: someUniqueUrlForTheNewMessageToBePostedTo |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <p>The client can then repeatedly POST the mesage to someUniqueUrlForTheNewMessageToBePostedTo until it gets a 200 OK which avoids duplicates.</p> |
| |
| <h4>Optional alternative for single request</h4> |
| |
| <p>If a smart client is capable of generating a system wide unique GUID (id) for the message, the server side could ignore duplicates. So posting to queue could be done without the double-request approach above</p> |
| |
| <structured-macro ac:macro-id="dc797621-e532-4c96-a49e-2a20bcb948af" ac:name="code" ac:schema-version="1"><plain-text-body> |
| POST /queues/foo.bar?guid=clientGeneratedUniqueId |
| --------------------> |
| |
| 200 OK |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| |
| <h3>Consuming from a queue</h3> |
| |
| <p>As described above, this is the tricky part of mapping message queues to REST. </p> |
| |
| <p>So we introduce a resource for a <em>subscription</em> to a queue. The subscription remains active until some timeout value - so a subscription is a sort of lease.</p> |
| |
| <p>When a subscription is created it can be given a variety of different pieces of data such as </p> |
| <ul><li>the <link><page ri:content-title="What is the Prefetch Limit For?"></page><link-body>prefetch buffer</link-body></link></li><li>what destinations it applies to (for example we could use wildcards)</li><li>whether a selector/filter is applied</li></ul> |
| |
| |
| <h4>Create a subscription</h4> |
| |
| <structured-macro ac:macro-id="d49de1c7-6395-4df3-8699-dab96e796744" ac:name="code" ac:schema-version="1"><plain-text-body> |
| POST /subscriptions |
| --------------------> |
| |
| 201 OK |
| Location: subscriptionUri |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <p>The actual subscription data could be form encoded key/value pairs.</p> |
| |
| <h4>Deleting a subscription</h4> |
| |
| <p>Good clients will delete subscriptions when they are no longer required; though they do timeout eventually.</p> |
| |
| <structured-macro ac:macro-id="6badd40e-e6f3-4b2c-af45-6ee2c6a8db8d" ac:name="code" ac:schema-version="1"><plain-text-body> |
| DELETE subscriptionUri |
| --------------------> |
| |
| 200 OK |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <h4>Consuming messages</h4> |
| |
| <p>You consume messages by browsing the subscription (like any APP resource) then DELETEing the message when you have finished processing it.</p> |
| |
| <structured-macro ac:macro-id="bfb180ae-ec58-4f0d-a60f-0467b961cf5f" ac:name="code" ac:schema-version="1"><plain-text-body> |
| GET subscriptionUri |
| --------------------> |
| |
| 200 OK |
| Atom Feed with one entry per message associated to this subscription |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <p>Then to acknowledge a particular message has been processed</p> |
| |
| <structured-macro ac:macro-id="2b9a473f-a596-45c3-9d91-d25aca26d9c2" ac:name="code" ac:schema-version="1"><plain-text-body> |
| DELETE messageUri |
| --------------------> |
| |
| 200 OK |
| <-------------------- |
| </plain-text-body></structured-macro> |
| |
| <h2>Deltas with APP</h2> |
| |
| <p>Almost all of the above could be just pure APP really. The only real difference is that each consumer has its own feed of messages which are to be consumed. </p> |
| |
| <p>In ActiveMQ's case, we use a <link><page ri:content-title="What is the Prefetch Limit For?"></page><link-body>prefetch value per consumer</link-body></link> to define how many messages each consumer gets in its buffer, before messages must be acknowledged to get more messages.</p> |
| |
| <p>So the idea is that we have a per-consumer feed which is created; it can then be browsed (by anyone with sufficient karma).</p> |
| |
| |
| |
| |
| |
| </div> |
| |