A One File .NET Micro Service Bus for MSMQ?

This last year our company has invested quite some time in looking at CQRS, which led to looking at great looking service-buses like nServiceBus, Rhino Service Bus and Mass Transit, which led me to do some bus-coding on my own, mostly for fun and for learning MSMQ.

Inspired by the service buses mentioned above, the result became a bare-bones-one-file “micro service bus” that I call MiniBuss which sits on top of MSMQ. The file itself is only some 400 lines of code and supports send, receive, reply, publish and subscribe/unsubscribe.

Setting up a sender may look something like this:

var bus = new MiniBuss.ServiceBus();

bus.RegisterMessageEndpoint<HelloCommand>("minibuss_receiver1@johan-dell-ssd");

bus.Start();

bus.Send(new HelloCommand { Guid = Guid.NewGuid(), Message = "Hello" });

Create the bus, register a message and tell it where messages of this type should go, start the bus and send the message.

Setting up a receiver may look something like this:

var bus = new ServiceBus { LocalEndpoint = "minibuss_receiver1" };

bus.RegisterMessageHandler<HelloCommand>(command => Console.WriteLine(command.Message + " Guid: " + command.Guid));

bus.Start();

Create the bus and tell it which endpoint to listen to (which creates a local MSMQ queue if necessary) and tell it which message type to listen for and which delegate to kick off when such a message is received.

Similarly, when doing a receive/reply, you would have to create the bus on the sender side with a local endpoint and register a message-handler for replies, like this:

var bus = new MiniBuss.ServiceBus { LocalEndpoint = "minibuss_sender1" };

bus.RegisterMessageEndpoint<HelloCommand>("minibuss_receiver1@johan-dell-ssd");

bus.RegisterMessageHandler<HelloResponse>(reply => Console.WriteLine("Reply from receiver: " + reply.Message));

bus.Start();

Console.WriteLine("Sending command...");
bus.Send(new HelloCommand { Guid = Guid.NewGuid(), Message = "Hello" });

The receiver would do a bus.reply() like this:

var bus = new ServiceBus { LocalEndpoint = "minibuss_receiver1" };

bus.RegisterMessageHandler<HelloCommand>(command =>
{
    Console.WriteLine(command.Message + " Guid: " + command.Guid);

    bus.Reply(new HelloResponse { Guid = Guid.NewGuid(), Message = "Hello back!" });
});

bus.Start();

The MiniBus also supports publish to multiple subscribers. A simple publisher would create a bus with a local endpoint (to receive subscribe/unsubscribe commands), tell it to handle subscriptions for a certain event, then start publishing something every 5 seconds (as an example):

var bus = new MiniBuss.ServiceBus { LocalEndpoint = "minibuss_publisher1" };

bus.HandleSubscriptionsFor<SomethingHappenedEvent>();

bus.Start();    

Task.Factory.StartNew(() => PublishingThread(bus), TaskCreationOptions.LongRunning);

Console.WriteLine("Done, press ENTER to exit");
Console.ReadLine();
private static void PublishingThread(MiniBuss.ServiceBus bus)
{
    while (true)
    {
        Thread.Sleep(5000);
        var guid = Guid.NewGuid();
        Console.WriteLine("Publishing event with guid " + guid);
        bus.Publish(new SomethingHappenedEvent() { Guid = guid, Sent = DateTime.Now });
    }
}

Any clients interesting in subscribing to events from the publisher would create a bus with a local endpoint, start the bus and then send a subscribe command to the publisher, telling it you’re interested in subscribing to a certain type of event and which delegate to handle it:

var bus = new MiniBuss.ServiceBus {LocalEndpoint = "minibuss_subscriber1"};

bus.Start();

bus.Subscribe<SomethingHappenedEvent>("minibuss_publisher1@localhost",
    @event => Console.WriteLine("something happened at {0}, event id {1}",
        @event.Sent, @event.Guid));

Console.WriteLine("Waiting for events, press ENTER to exit");
Console.ReadLine();

bus.UnSubscribe<SomethingHappenedEvent>("minibuss_publisher1");

Now, the question is, what do you think? I know there are issues with the code, like how to make message-handlers multi-threaded/concurrent without messing things up (it’s single threaded right now), and how to best handle exceptions, rollbacks and re-tries . Right now handling exceptions in send and receive works pretty well within a TransactionScope() together with ADO.NET, and if there’s an exception, the message is moved the an error-queue. No re-try or anything, only rollback and move to xxx_error. Also, the publisher doesn’t persist subscriptions, so if it is restarted subscribers wouldn’t know. You know, things like that.

I’m a user of the micro-orm called Dapper and like it a lot, so I’m thinking that maybe I should release this micro-bus as open source and see where people may take it, if anywhere? Maybe just down the drain because they figure out this service bus is dangerous to use and risk loosing messages or something (which would be extremely good to know :)

Or maybe this code is useless because you already got nServiceBus and Rhino out there and coders don’t need another service bus?

What do you say?

9 Comments

  • Really like the look of this! I'm a big fan of micro frameworks and I was just about to start looking at nServiceBus or similar.

    Would love to see it on github and/or NuGet!

  • I love the idea and actually started to think about this a couple of days ago.

    I would be happy to contribute, if you decide to go open source.

  • Thanks for the quick feedback - if I decide to go open source, which repository would you prefer? I'm used to codeplex myself, but github works too I guess :)

    @Jose - I would love to get help on both reviewing/testing and coding if I release the stuff. It's very "spiky" atm ;)

  • @Anders - if released on NuGet, should it be adding ref to the small dll or injecting the code file? Sam changed Dapper from dll to the code/source file. Not sure which is best?

  • I'm really not picky. CodePlex, BitBucket or any other. PM me at twitter @zepedro

  • Looks good at a first sight.

    I would prefer the Nuget package as a single file.

    Personally, I think that's one of the main benefits of all theese single-file micro frameworks. No external dependencies, no extra files to include, easy to modify etc.

  • I've created a codeplex project for this now (not open yet), and I've also created a NuGet package locally for testing.

    Will try to open upp everything in the next couple of days and would love to get more people aboard - both devs and testers. Especially people who knows concurrency and will be able to break it :)

  • Really interesting project,
    I think nServiceBus as a too restrictive licensing, and Rhino forces to use Castle, that is becaming huge. An alternative is Mass Transit, that does not have the concept of permanent subscription/transient substcription, so I would love to see this in your project ( these concepts comes from ActiveMQ ). If you accept cooperation on your project, I would be happy to join it.

  • Just opened up a codeplex site for this project at http://minibuss.codeplex.com will also open it up for co-op soon.

    Will also publish a NuGet installer today called "MiniBuss".

Comments have been disabled for this content.