A user requested Selector support. Follow the links and doco from:
To download, etc. The next REST-* messaging spec will be derived from this after hornetq user feedback.
A user requested Selector support. Follow the links and doco from:
To download, etc. The next REST-* messaging spec will be derived from this after hornetq user feedback.
I’ve made some small changes to REST-* Message Draft 5. First is to the reliable posting of messages to a message destination. The second is to the push model default subscription creation method.
New post-message-once protocol
Previously, the post-message-once link used the POE pattern to avoid duplicate message posting. I asked around and it seems that the POE pattern isn’t used a lot in practice. I’m glad because it kinda breaks the uniform interface (unsafe GET) and isn’t really consistent with the other protocols I defined. It is also very inefficient as you have to make two round trips to post each message. Nathan Winder, on the reststar-messaging list suggested using a one-off link generated with each message post. Here’s how it looks:
The post-message-once link URL provided by this link is not used to actually create a message, but rather to obtain a new, one-off, URL. An empty POST should be executed on the post-message-once link. The response provides a new “create-next” link which the client can then post their message to. The link is a “one-off” URL. What that means is that is that if the client re-posts the message to the create-next URL it will receive a 405 error response if the message has already successfully been posted to that URL. If the client receives a successful response or a 405 response, there should be a Link header returned containing a new “create-next” link that the client can post new messages to. Continuously providing a “create-next” link allows the client to avoid making two round-trip requests each and every time it wants to post a message to the destination resource. It is up to the server on whether the create-next URL is a permanent URL for the created message. If it is not permanent, the server should return a Content-Location header to the message.
post-message-once example
HEAD /topics/mytopic HTTP/1.1 Host: example.com
Response:
HTTP/1.1 200 OK
Link: <...>; rel="post-message",
<...>; rel="post-batch",
<http://example.com/topics/mytopic/messages>; rel="post-message-once",
<...>; rel="message-factory"
POST /topics/mytopic/messages Host: example.com
Response:
HTTP/1.1 200 OK Link: <http://example.com/topics/mytopic/messages/111>; rel="create-next"
POST /topics/mytopic/messages/111
Host: example.com
Content-Type: application/json
{'something' : 'abitrary'}
Response:
HTTP/1.1 200 Ok Link: <http://example.com/topics/mytopic/messages/112>; rel="create-next"
Change to push model subscription
I also added a minor change to the push model’s subscriber registration protocol. In the previous version of the spec, the client would post form parameters to a subscribers URL on the server. The form parameter would define a URL to forward messages to and whether or not to use the POE protocol to post this message. I changed this to simple require the client to post an Atom Link. Since links define protocol semantics, the server can look at the link relationship registered to know how to interact with the subscriber when forwarding messages. So, if the client registers a post-message-once link when it creates its subscription, the server knows how to interact with the link. This gives the client and server a lot of simple flexibility in describing how messages should be forwarded. For example:
This example shows the creation of a subscription and the receiving of a message by the subscriber.
HEAD /mytopic Host: example.com
Response:
HTTP/1.1 200 OK
Link: <http://example.com/mytopic/subscribers, rel=subscribers, type=application/atom+xml
...
POST /mytopic/subscribers Host: example.com Content-Type: applicatin/atom+xml <atom:link rel="post-message-once" href="http://foo.com/messages"/>
Response:
HTTP/1.1 201 Created Location: /mytopic/subscribers/333
POST /messages Host: foo.com
Response:
HTTP/1.1 200 OK Link: <http://foo.com/messages/624>; rel=create-next
Request:
POST /messages/624
Host: foo.com
Link: <http://example.com/mytopic/messages/111>; rel=self,
<http://example.com/mytopic>; rel=generator
Content-Type: whatever
body whateve
Just finished draft 4 of REST-* Messaging. Please check our our discussion group if you want to talk more about it. Here’s a list of resources and their corresponding relationships for a high level overview. See the spec for more details. It relies heavily on Link headers. The current draft shows a lot of example HTTP request/responses to give you a good idea of what is going on.
Destination
A queue or a topic resource.
Relationships:
Message
Every message posted creates a message resource that can be viewed for adminstration, auditing, monitoring, or usage.
Links Relationships:
Topic
Has the same links as Destination with these added:
Link Relationships:
Queue
Same as Destination, but these additional link relationships:
Link Relationships:
I wanted to add acknowledgement to the queue consumer pull model in REST-* Messaging. The way it would work is that consumers do a POST on the queue’s URL. They receive the message as well as a Link header pointing to an acknowledgement resource. When the client consumer successfully processes the message, it posts a form parameter, acknowledge=true to the acknowledgement link.
There is a problem with this though. The design is connectionless to honor the stateless REST principle. So there is no specific session resource that the client consumer is interacting with. The consumer may never acknowledge the message, so I need the server to re-enqueue the message and deliver it to a new consumer. The problem is, what if the old consumer tries to acknowledge after the message is re-enqueued or even after it is redelivered to a different consumer?
I first thought of letting the first consumer to acknowledge win and do something like POST-Once-Exactly (POE). The problem with this is, what if there’s a network failure and the consumer doesn’t know if the acknowledgement happened or not? It would redeliver the message and get back a Method Not Allowed response error code. With this code, the consumer doesn’t know if somebody else acknowledged the message or if the older request just went through. At first, I thought about in my personal blog of doing a conditional POST using ETag and If-Match. The acknowledgement link, when performing a GET on it, would return an ETag header that the consumer must transmit with the acknowledgement POST. If the message was re-enqueued, then the underlying ETag would change, and the conditional post would fail for the older consumer.
On my blog comments, Mike Amundsen pointed out that you can embed the etag information directly within the URL. Then, the client does not have to be aware of the of the conditional POST requirement and can just POE to the ack link. You also save on the extra GET request to obtain the ETag header of the resource. The protocol would look something like this:
1. Consume a messageRequest:
POST /myqueue/consumer
Response:
HTTP/1.1 200 OK Link: </myqueue/messages/111/acknowledgement;etag=1>; rel=acknowledgement Content-Type: ... ... body ...
2. Acknowledge the message. Its just a POST back tot he URL. Remember this is a POE link so if the consumer has to redeliver the POST, the request may return a 405, method not allowed. Also notice that there is a matrix parameter named etag within the ack URL. The server will use this information to determine if the correct consumer is acknowledging.
Request:
POST /myqueue/messages/111/acknowledgement;etag=1 Content-Type: application/x-www-form-urlencoded acknowledge=true
Success Response:
HTTP/1.1 204 No Content
Response when it was updated by somebody else.
HTTP/1.1 412 Precondition Failed
POE Redelivery Response. It was already successfully updated by the consumer.
HTTP/1.1 405 Method Not Allowed
I wonder if I even need the POE semantics with this. I guess it doesn’t matter if the request is redelivered.
One thing the HTTP specification does not have is a “Server Timeout” response code. The 408 and 504 response codes are the only thing that comes close. The idea of a “Server Timeout” code is that the server received the request, but timed out internally trying to process the request. Another thing I think that is missing from HTTP is a way for the client to tell the server how long it is willing to wait for a request to be processed.
I’ve run into both of these scenarios with the REST-* Messaging specification when I have pulling client consumers. For the “Server Timeout” I decided upon 202, Accepted. It seems to fit as I can tell the client to try again at a specific URL. As for the client requesting a wait time? I invented a new request header: “X-RS-Wait”. Its value is the time in seconds that the client wants to wait for a request to be processed. Maybe there is a standard or drafted protocol I missed in my Google search?
After prototyping, I’m back to writing another draft. This is a little bit more formal draft. I created a OSS project at:
http://sf.net/projects/rest-star
A draft of the PDF is at:
http://reststar-messaging.googlegroups.com/web/REST-Star-Messaging-draft-3.pdf
(You’ll have to click through an additional link that is *very* long). This draft only talks about the Message Publishing Protocol. I still have to write up the topic and queue push and pull model. To discuss the draft please post at the REST-* Messaging Group. I’m also looking for people to help prototype the specification. Post to the RESTEasy developers list if you’re interested.