RestMS Published

Finally, we finished a draft of RestMS and published it on the AMQP specifications wiki. A lot went into that design, and here is some background.

After about six months, the first draft of RestMS is ready and got published on http://wiki.amqp.org/spec:7. It was tricky to get RestMS into shape. AMQP is not as elegant as it could be. Its concepts of exchange, shared queue, and private queue divide a large territory uneasily, like allies squatting over a conquered land. At first sight, the queues seem to have more in common with each other, and this is how AMQP divides them. Queues to the left, exchanges to the right, and bindings between them.

But if you look really carefully you start to see that this is not accurate. Private queues and shared queues are really different things. So much, that in OpenAMQ we shifted private queues to the client side, in Direct Mode, giving us much better performance and reliability. Putting private queues on the server turns out to be a bad idea.

And shared queues… why are these explicitly different from exchanges? Just so we can hide shared queues behind a binding? Sounds fun, but in practice, no-one does this. Shared queues are first class application objects, they represent resources that apps need to address directly. Very different from private queues.

What if, I thought, shared queues were just exchanges with storage. Instead of distributing messages by routing key or by topic matching, distribute them by round-robin. Turn this around, why not provide exchanges with storage? This would make sense, especially in an asynchronous messaging system. And make that storage orthogonally persistent or transient, and you start to get a design that feels general and clean enough for AMQP/1.0.

But this blog entry is about RestMS, not AMQP/1.0. With some delicate design, it became possible to hide AMQP's inelegant model behind something cleaner, and thus for RestMS we ended up with feeds, pipes, joins, and addresses. These concepts feel right: simple, familiar to many users, and yet coherent with what we're doing in AMQP.

To make this work in a RESTful API, we define URIs for each resource and methods on those URIs. All methods except POST should be idempotent - an application can do them several times with no further consequences. So, GET methods should have no side effects, PUT and DELETE should be idempotent.

Feeds and pipes fall into classes, each with particular semantics. In some cases applications need to know the class, since the way the feed routes messages, or a pipe delivers them, are part of interoperability. In other cases, the class can be left unspecified. The URIs in each case make this work neatly.

This works for working with all entities except messages. Doing idempotent, asynchronous message delivery is really not easy, if one wants to deliver real-world performance. To do RESTful access to a message would mean first querying the pipe as to all messages it contained, then fetching these messages, then deleting them. Slow, chatty, and complex.

So RestMS has a few different ways of accessing messages, from pedantic one-by-one delivery, to the stream class for pipes, which delivers messages as rapidly as the network can carry them. Applications don't poll, instead they wait on messages and then receive them as soon as they arrive in their pipes.

The proof of the pudding is always the silence of satisfaction as the assembled guests wolf it down accompanied by a glass of red wine. And the proof of a specification is the ease of implementation.

It took several attempts to get RestMS into shape. I started the first in August 2008, while on a trip to Togo, and I finished the last when back in Togo during the first weeks of December 2008. The software followed along, and as RestMS solidified, Zyre started to fall into shape.

Today is 23 December, and I'm still counting on releasing the first version of Zyre on Xmas 2008.

Happy RestMAS!

Add a New Comment
Page tags: front