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. So, I went with a conditional POST. 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.
Still this solution is suboptimal because an additional GET request needs to be executed. It is also subject to a race condition. What if the message is re-enqueued before the consumer does a GET on the acknowledgement resource? SO, what I decided to do was embed the etag value with the acknowledgement link. For example:
1. Consume a message
HTTP/1.1 200 OK Link: </myqueue/messages/111/acknowledgement>; rel=acknowledgement; etag=1 Content-Type: ... ... body ...
2. Acknowledge the message
POST /myqueue/messages/111/acknowledgement If-Match: 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