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:
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.
POST /myqueue/messages/111/acknowledgement;etag=1 Content-Type: application/x-www-form-urlencoded acknowledge=true
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.