Albeit under-specified and limited in functionality, STOMP is made attractive by its utter simplicity if you're OK with basic message queues. Yet, there are very few usable STOMP brokers. Indeed, the list seems to boil down to RabbitMQ. (The dissonance between ActiveMQ's overall "enterprise-ness" and its inability to manage more than a few hundred queues at once is remarkable.) I'm not especially attached to STOMP or RabbitMQ, but it's the simplest way I've found so far to get what I want:
persistent queues
topics (messages broadcast to all subscribers)
blocking receive (no polling)
message acknowledgement
scaling over many queues/topics
simplicity! Self-contained executable with small footprint preferable to huge ball of mud.
optional NACK and message locking (delivery of message unless ACKed within a given period)
RabbitMQ + STOMP satisfies all but the (two?) last item(s). I have yet to determine if it's possible to configure queues so that messages are considered dropped (and thus redelivered) if not acknowledged within a specified period of time. Is this doable in RabbitMQ (configuring timeout periods externally is OK)?
I read somewhere that RabbitMQ took some ~5KLoC of Erlang, so it shouldn't take much more than maybe 2KLoC or so worth of OCaml to implement the above, since I'm leaving out:
scaling over thousands of clients
extremely high message rates (thousands per second is amply sufficient)
queue replication
For now, I'm giving RabbitMQ a try. Unfortunately, RabbitMQ's STOMP adapter is also under-documented, so I had to discover most of the semantics by trial and error. Here's what I found.
Frames
Frames are delimited by a NUL character (\000), not a NUL character followed by a newline (\000\n), unlike ActiveMQ. Headers used to be of the form key:value (with no space), but the latest version trims leading spaces.
Queues
Queues can have the "auto-delete" property, which means that the queue (and thus all its messages) will disappear when the last client subscribed to it unsubscribes or disconnects. Queues are automatically created the first time they are subscribed to. This is how you create/subscribe to a persistent queue: