Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,124 | Comments: 45,475

filter by tags archive

Raven MQ – Client API Design

time to read 4 min | 768 words

There are only two topics that remains in the Raven MQ server (replication & point to point messaging), but I decided to stop for a while and focus on the client API. My experience have shown that it is so much more important than anything else to gain acceptance for the project.

One thing that I want to make clear is that this is the high level API, which has very little to do with how this is actually implemented.

The first thing to be aware of is that Raven MQ is transactional. That is, all operations either complete successfully or fail as a single unit. That makes it very easy to work with it for a set of scenarios. It is not an accident that the API is very similar to the one that you get from Rhino Service Bus or NServiceBus, although Raven MQ client API is drastically more modest in what it is trying to do.

Getting started:

var raveMQEndpoint = new RavenMQEndpoint
    Url = "http://localhost:8181"

Subscribing (methods):

raveMQEndpoint.Subscribe("/streams/system/notifications", (ctx, untypedMsg) =>
    // do something with the msg

raveMQEndpoint.Subscribe<LoginAboutToExpire>("/streams/user/1234", (ctx, msg) =>
    // do something with the msg

raveMQEndpoint.Subscribe<LoginExpired>("/streams/user/1234", (ctx, msg) =>
    // do something with the msg

This allows you to handle untyped messaged, or to select specific types of messages that will be handled from the stream (ignoring messages not of this type). I’ll discuss the ctx parameter at a later stage, for now, you can ignore it. What you can’t see here is that the Subscribe methods here returns an IDisposable instance, which allows you to remove the subscription. Useful for temporary subscriptions, which is something that is pretty common for the scenarios that we see Raven MQ used for.

Subscribing (classes):

raveMQEndpoint.Subscribe("/streams/user/1234", () => new LoginExpiredConsumer());

raveMQEndpoint.Subscribe("/streams/user/1234", mefContainer);

Instead of registering a single method, you can register a factory method, or a MEF container, both of which will create a consumer class for handling the messages.


Raven MQ doesn’t care about the serialization format, you can it messages using whatever format you like, but the client API used JSON/BSON to store the data.

Sending messages:

Remember that I talked about the ctx parameter? The RavenMQEndpoint doesn’t offer a Send() method, that is handled by the ctx paratemer, which stands for Context, obviously. The idea is quite simple, we want to make message sending transactional, so we always use a context to send them, and only if the context completed successfully can we truly consume the message and send all the messages to the server. You can think of the Context as the Raven MQ transaction.

For sending messages outside of processing an existing message, you can use:

ravenMQEndpoint.Transaction(ctx=> ctx.Send("/queues/customers/1234", updateCustomerAddress));

This gives us a very easy way of scoping multiple messages in a single transaction without awkward APIs.




Looks tough.... ;)


where can I get this? really impress me about REST style interaction!!



I'm waiting to play with! I'm curious about the client api capabilities in a javascript environment, and I'm courios also to take a look to the code.

Just one thing, I don't really feel comfortable with the message sending, because it seems a little bit ... difficult (sorry but words that cames in mi mind in italian could be translated just with "difficult")


As far as I see, you tend to close the whole message processing in an action to have it wrapped with a transaction. Am I getting it right?

What about passed MEF container. Is is asked about all of the listeners/handlers of the specific message? If so, the DI in your handlers is saved!:D

Tom Dietrich

To modify an old internet meme, "This Thread Is Useless Without Sourcecode!"

Stop teasing me and let me under the hood already!

Chris Patterson

Great to see some code snippets escaping, now on to some comments.

You are using the concept of an endpoint, but since the queues are specified after the endpoint, aren't you really creating a connection or a channel to the queue service. A multiplex channel to RavenMQ seems to make sense from a naming perspective.

On the subscribe semantics, could we combine the arguments into a pair of types, one for untyped and one for typed messages? My message handling methods could be:

void Handle(RavenMQ.Message msg)


string body = Encoding.GetString(msg.Body);



Or for a typed message

void Handle(RavenMQ.Message <accountchanged msg)


_cache[msg.Body.AccountId] = msg.Body.Account;



That way additional methods could be added to the Message or Message <t interfaces, and extension methods could be used to extend/simplify the syntax for things like publishing events, responding to requests, etc.

Just some ideas...

Chris Patterson

Gah, it stripped my Message tag from the second Handle method.

Ayende Rahien


Thanks, I'll probably apply both suggestions

Frank Quednau

These transactions then, you are just stating that a send is successful when you know it will be readable by other subscriptions, or are you getting into some distributed stuff?

Ayende Rahien


If you have local tx, you can easily get distributed tx.

Comment preview

Comments have been closed on this topic.


  1. The design of RavenDB 4.0: Making Lucene reliable - 16 minutes from now
  2. RavenDB 3.5 whirl wind tour: I’ll find who is taking my I/O bandwidth and they SHALL pay - about one day from now
  3. The design of RavenDB 4.0: Physically segregating collections - 2 days from now
  4. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - 3 days from now
  5. RavenDB 3.5 whirl wind tour: I'll have the 3+1 goodies to go, please - 6 days from now

And 13 more posts are pending...

There are posts all the way to May 30, 2016


  1. RavenDB 3.5 whirl wind tour (14):
    02 May 2016 - You want all the data, you can’t handle all the data
  2. The design of RavenDB 4.0 (13):
    28 Apr 2016 - The implications of the blittable format
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series



Main feed Feed Stats
Comments feed   Comments Feed Stats