Simon Timms's Picture

Simon Timms

265 posts

Some Clarity on my Thoughts on NServiceBus

In my last blog post I mentioned in passing something about NServiceBus

There is, of course, a cost to running NServiceBus as it is a commercial product. In my mind the cost of NServiceBus is well worth it for small and medium installations. For large installations, I'd recommend building more tightly on top of cloud based transports, but that's a topic for another blog post.  

I though that, perhaps, there should be some clarity to my comments. I have a few good friends who make their living working with NServiceBus and there was some debate about my point.

MassTransit is a competitor to NServiceBus and I'd also say that Akka.NET plays in a similar enough space to be considered competition. However, one of the biggest competitors is hubris. The belief, by developers, that they can build NServiceBus in an afternoon. Afterall it is just a sprinkling of dependency injection on top of a transport protocol and mixed with a sprinkle of quartz.net, right?

I fell into that trap some years ago. The company I was with needed a service bus but wasn't willing to spend the money on NServiceBus. They had almost a dozen servers handling messages so the cost would have been pretty significant. I took a full month to build what was a prety limited version of NServicebus. It was an adventure and the result was, almost certainly, full of bugs. Hundreds of unit tests can uncover and verify a lot but when it comes to distirbuted, multi-processor systems the bugs tend to be, well, interesting. Building NServiceBus is jolly hard.

This is the old build vs. buy dilema rearing it's head. The cost of building and maintaining a system the equivilent to NServieBus is huge. You would need to have a large team dedicated to it. However you don't necessarily need to build the entirety of NServieBus. That's the crux of my comment: in large systems you may wish to build your own, thinner, interface over a messaging system like Azure Service Bus: one which exposes a smaller, more focused API. Balancing build and buy is one of the more difficult things to get right in software.

Consider a system like LMAX: it was a highly focused, message based architecture. It would not have been suitable for NServiceBus because they had performance needs which were well outside of NServiceBus' capabilities. Specific needs are another reason you might want to build your own system.

I suspect that more than 95% of distributed systems written in .NET are suitable for simply using NServiceBus. It is that final few percent where the needs are unusual or specific enough to require a custom build.

So should you buy NServiceBus? If your needs are for a reliable distributed system with top tier support then probably. If you have a massive system to build or narrow needs then you may wish to explore further. But, be warned, building distributed frameworks is exceedingly non-trivial.

MassTransit on RabbitMQ in ASP.NET Core

In the last post, we created an application which can send tasks to a background processor. We did it directly with RabbitMQ which was a bit of a pain. We had to do our own wiring and even our own serialization. Nobody wants to do that for any sort of sizable application. Wiring would be very painful on a large scale.

There are a couple of good options in the .NET space which can be layered on top of raw queues. NServiceBus is perhaps the most well know option. There is, of course, a cost to running NServiceBus as it is a commercial product. In my mind the cost of NServiceBus is well worth it for small and medium installations. For large installations I'd recommend building more tightly on top of cloud based transports, but that's a topic for another blog post.

MassTransit is another great option. Comparing the two is beyond the scope of this article but there are some good articles on that already. MassTransit layer an actual messaging layer on top of either RabbitMQ or Azure Service Bus which means that is provides for serialization and routing.

We should, perhaps, take a moment here to talk about the two types of messages we use in a message driven system. The first is a command. Commands are instructions to perform some action. They are named in the imperative such as

  • AddUser
  • DeleteAccount
  • PlantFlowers

Commands can be validated and rejected by a command handler if they are invalid. A command can be sent from multiple points in the code but is consumed by a single endpoint, consumer or command handler. The message bus handles the association of commands and command handlers.

The second type of message is an event. It is a notificaiton that something has happened. It cannot be rejected by a handler because it is something which has already happened - you can't change the past. Typically, they are named in the past tense

  • UserAdded
  • AccountDeleted
  • FlowersPlanted

An event is raised in a single location but may be consumed by many services. Events are typically raised as a result of a command, however they need not be 1:1. Consider handling the AddUser command: during the processing we might raise a number of events UserAdded, UserAddedToDatabase, UserAddedToSearchEngine, WelcomeEmailSent. Events provide a powerful mechanism for decoupling components. Parts of the code base interested in the UserAdded event can subscribe to the messages without the add user consumer knowing about them. This cleanly splits responsibilities.

Returning to MassTransit we will create an example web application which sends commands and a console application which consumes messages. Let's start start building the message producer first. A number of packages will need to be added to the project.json

    "MassTransit": "3.5.5",
    "MassTransit.RabbitMQ": "3.5.5",
    "Common": "1.0.0-*",
    "Autofac.Extensions.DependencyInjection": "4.0.0",

The MassTransit and MassTransit packages provide the backbone of MassTransit and the bindings to RabbitMQ. Autofac will be used to handle the dependency injection of complex objects. The build in DI system might be sufficient but I have a preference for Autofac. Finally, the Common project contains the message interfaces. MassTransit will hydrate new messages for us based on interfaces so we don't actually have to construct concrete classes. The nice part is that this effectivly enables multiple inheritance.

In our example, we're going to use an AddUser message. You can tell from its name that it is a command.

public interface AddUser  
{
    string FirstName { get; set; }
    string LastName { get; set; }
    string Password { get; set; }
    string EmailAddress { get; set; }
}

The bus can now be configured in our StartUp.cs up class.

public IServiceProvider ConfigureServices(IServiceCollection services)  
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);
    services.AddMvc();

    var builder = new ContainerBuilder();
    builder.Register(c =>
    {
        return Bus.Factory.CreateUsingRabbitMq(sbc => 
            sbc.Host("172.22.149.120", "/", h =>
            {
                h.Username("guest");
                h.Password("guest");
            })
        );
    })
    .As<IBusControl>()
    .As<IBus>()
    .As<IPublishEndpoint>()
    .SingleInstance();
    builder.Populate(services);
    container = builder.Build();

    // Create the IServiceProvider based on the container.
    return new AutofacServiceProvider(container);
}

Here we set up the the bus and give it the rabbitMQ connection settings. I hard coded the connection information here but that's bad. You can easily access the Configruation and pull values from that, we'll do that in another post

In the configure method we can resolve the bus control and start it up

var bus = container.Resolve<IBusControl>();  
var busHandle = TaskUtil.Await(() => bus.StartAsync());  

It is also polite to shut down the bus one application exit. This was difficult in previous versions of ASP.net/WebAPI but it is now simple. We just add an IApplicationLifetime lifetime to the Configure method and then

lifetime.ApplicationStopping.Register(() => busHandle.Stop());  

Now we can get to actually sending a message. We'll do that right from the controller, because we roll that way. In something like NServiceBus 5 we send messages by writing them to the bus directly. In NSB 6 this changed to use an endpoint, which is a bus in all but name. MassTransit also has a concept of an endpoint and, I'd say, it is closer to what I think of as an endpoint than what NSB uses. An endpoint is a destination to send a message. We can ask the MassTransit bus object to generate us an endpoint.

IBus _bus;  
public HomeController(IBus bus)  
{
    _bus = bus;
}
public async Task<IActionResult> Index()  
{
    var addUserEndpoint = await _bus.GetSendEndpoint(new Uri("rabbitmq://172.22.149.120/AddUser1"));

Again you can see that we have a bit of a reliance on some hard coded strings. We'll look at addressing some of this in a later post. For now it sufices to observe that we send to a specific address. Once we have the endpoint we can send the message

 await addUserEndpoint.Send<AddUser>(new 
{
    FirstName = "Simon",
    LastName="Tibbs",
    EmailAddress="stimms@gmail.com",
    Password = "A wicked secret password"
});

That's enough to get a message into the RabbitMQ. We can now set up a message consumer on the other end. For this we'll stand up a new command line program, shove a bus in it and hook up a consumer. Sounds like a lot but it is actually pretty simple. In our program entry point, typically Program.cs we build the bus.

var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>  
{
    var host = cfg.Host(new Uri("rabbitmq://172.22.149.120/"), h =>
    {
        h.Username("guest");
        h.Password("guest");
    });

    cfg.ReceiveEndpoint(host, "AddUser1", e =>
    {
        e.Consumer<AddUserConsumer>();
    });
});
busControl.Start();  

Notice that we add a consumer endpoint called AddUserConsumer. A consumer is a piece of code which is executed when a matching message is received. In this case all we want to do is log out to the console

public class AddUserConsumer : IConsumer<AddUser>  
{
    public Task Consume(ConsumeContext<AddUser> context)
    {
        Console.WriteLine($"Adding user {context.Message.FirstName} {context.Message.LastName}");
        return Task.CompletedTask;
    }
}

The AddUserConsumer's Consume method will be called by MassTransit any time that it is fed a message by RabbitMQ. This method of wiring up handler or consumers is much cleaner and more scalable than what we saw with using raw RabbitMQ.

Another thing you might have noticed with the MassTransit code is that it is all asynchronous. This is a nice feature, especially because the handler contexts will tend to have asynchronous things happening in the: writing to a database, sending http requests and so forth.

The title of this post mentions .NET Core but unfortunately MassTransit and RabbitMQ don't curently run on .NET Core so this needs to be run on full framework. I suspect that when netstandard 2 and .NET Core 2 come online later in 2017 it will be possible to run using that, possibly even across platforms.

In the next post we'll look at including DI to wiring of our consumers and also clean up some of the hard coded strings we have scattered about.

Getting Started with RabbitMQ in ASP.NET

Orignally posted to the ASP.NET Monsters blog at https://aspnetmonsters.com/2017/03/2017-03-18-RabbitMQ%20from%20ASP/

In the last post we looked at how to set up RabbitMQ in a Windows container. It was quite the adventure and I'm sure it was woth the time I invested. Probably. Now we have it set up we can get to writing an application using it.

A pretty common use case when building a web application is that we want to do some background processing which takes longer than we'd like to keep a request open for. Doing so would lock up an IIS thread too, which ins't optimal. In this example we'd like to make our user creation a background process.

To start we need a command which is just a plain old CLR object

public class AddUser  
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string EmailAddress { get; set; }
}

That all looks pretty standard. In our controller, we'll just use the handy UserCreationSender

public class HomeController : Controller  
{
    IUserCreationSender _userCreationSender;
    public HomeController(IUserCreationSender userCreationSender)
    {
        _userCreationSender = userCreationSender;
    }

    public IActionResult Index()
    {
        _userCreationSender.Send("simon", "tibbs", "stimms@gmail.com");
        return View();
    }
}

There that was easy. In our next post, we'll... what's that? I've missed actually showing any implementation. Fair point, we can do that.

public void Send(string firstName, string lastName, string emailAddress)  
{
    var factory = new ConnectionFactory()
    {
        HostName = "172.22.144.236",
        Port = 5672,
        UserName = "guest",
        Password = "guest"
    };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.QueueDeclare(queue: "niftyqueue",
                                durable: false,
                                exclusive: false,
                                autoDelete: false,
                                arguments: null);

        var command = new AddUser
        {
            FirstName = firstName,
            LastName = lastName,
            EmailAddress = emailAddress,
            Password = "examplePassword"
        };
        string message = JsonConvert.SerializeObject(command);
        var body = Encoding.UTF8.GetBytes(message);

        channel.BasicPublish(exchange: "",
                                routingKey: "niftyqueue",
                                basicProperties: null,
                                body: body);
    }
}

Values here are hard coded which we don't want to do usually, check out https://aspnetmonsters.com/2016/01/Configuration-in-ASP-NET-Core-MVC/ for how to pull in configuration. Ignoring that we start by creating a conneciton factory with connection information for RabbitMQ. We then create a new queue (or ensure that it already exists) called "niftyqueue". There are some other parameters in the queue creation we can get into in a future article.

Next we'll create an AddUser command and serialize it to JSON using good old Json.net then get the bytes. Rabbit messages contain a byte array so we have to do a tiny bit of leg work to get our CLR object into a form usable by the transport. JSON is the standard for everything these days so we'll go with the flow. In a real system you might want to investigate Protocol Buffer or something else.

Finally we perform a basic publish, sending our message. The Rabbit management site provides a super cool view of the messages being published on it

The dashboard

How cool is that? Man I like real time charts.

Shoving messages into the bus is half the equation, the other half is getting it out again. We want to have a separate process handle getting the message. That looks quite similar to the message sending.

public static void Main(string[] args)  
{
    Console.WriteLine("starting consumption");
    var factory = new ConnectionFactory()
    {
        HostName = "172.22.144.236",
        Port = 5672,
        UserName = "guest",
        Password = "guest"
    };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.QueueDeclare(queue: "niftyqueue",
                                durable: false,
                                exclusive: false,
                                autoDelete: false,
                                arguments: null);

        var consumer = new EventingBasicConsumer(channel);
        consumer.Received += (model, ea) =>
        {
            var body = ea.Body;
            var message = Encoding.UTF8.GetString(body);
            var deserialized = JsonConvert.DeserializeObject<AddUser>(message);
            Console.WriteLine("Creating user {0} {1}", deserialized.FirstName, deserialized.LastName);
        };
        channel.BasicConsume(queue: "niftyqueue",
                                noAck: true,
                                consumer: consumer);

        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

Again we create the factory and the queue (some opportunity there for refactoring, me thinks). Next we start up an EventingBasicConsumer on top of the channel. There are a couple of different ways to consume messages none of which I really love. The eventing model seem the leas objectionable. You simply assign a delegate to the event handler and it will fire when a message is recieved.

In the next post I'll start taking a look at how we can layer MassTransit, a .NET message bus, on top of raw RabbitMQ. The result is a much more pleasant experience then simply hammering together raw RabbitMQ.

Creating a Rabbit MQ Container

Originally posted to the ASP.NET Monsters blog at https://aspnetmonsters.com/2017/03/2017-03-09-rabbitmq/

I bought a new laptop, a Dell XPS 15 and my oh my is it snazzy. The thing I was most excited about was that I'd get to play with Windows containers again. I have 3 other machines in the house but they're either unsuitable for containers (OSX running Windows in parallels) or I've so toally borked them playing with early betas of containers they need to be formatted and reinstalled - possibly also thrown into the sun.

So when I found myself presented with the question "how can we get into messaging in our apps for free?" I figured I'd crack open the laptop and build something with MassTransit. I found that MassTransit supports running on RabbitMQ. Why that sounds like a perfect opportunity to deploy RabbitMQ to a container. Only problem was that I didn't really know how to do that.

In my heart I felt like running the installer wasn't quite the right way to go. I'd just copy the installation file into their destination. Problem is that RabbitMQ relies on erlang so I'd have to install that too. I build a docker file which looked something like

FROM microsoft/windowsservercore  
ENV rabbitSourceDir "RabbitMQ Server"  
ENV erlngDir "C:/program files/erl8.2/"  
ENV rabbitDir "C:/program files/RabbitMQ Server/"  
ADD ${rabbitSourceDir} ${rabbitDir}  
ADD erl8.2 ${erlngDir}  
ENV ERLANG_HOME "c:\program files\erl8.2\erts-8.2"  

In the erlngDir and rabbitDir I dumped the contents of an install of erlang and rabbitmq. Then I built the container with

docker build -t monsters/rabbitmq .

Didn't work. There must be something useful the installer actually does as part of installing files. So next I considered putting in the installers and running them when building the container. That seemed like a huge pain so I got to thinking about using chocolatey. At first I was pretty deadset against using choco my reasoning being that containers should be lightweight and have only one purpose. Having one time software like chocolatey on there which wouldn't ever be used seemed like it would make... whoever invented containers mad.

So attempt number two:

FROM microsoft/windowsservercore

#install chocolatey
RUN @powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"

#install rabbitmq
RUN choco install -y rabbitmq

That was enough to get Rabbit MQ installed. I still needed to expose some ports for RabbitMQ so I added

####### PORTS ########
#Main rabbitmq port
EXPOSE 5672  
#port mapper daemon (epmd)
EXPOSE 4369  
#inet_dist_listen
EXPOSE 35197  
#rabbitmq management console
EXPOSE 15672  

Rabbit also likes to know where Erlang lives so some environmental variables for that aren't going to hurt.

#set the home directory for erlang so rabbit can find it easily
ENV ERLANG_HOME "c:\program files\erl8.2\erts-8.2"  
ENV ERLANG_SERVICE_MANAGER_PATH "c:\program files\erl8.2\erts-8.2"  

We could forward the RabbitMQ ports to our local machine but I like the idea of using the container as if it were a distinct machine so let's also enable the management UI from anywhere on the network. To do that we'll replace the default config file with one that has

{loopback_users, []},

in it. We can copy our new config file over the one in the container from the dockerfile and set up a variable to point Rabbit at it.

ENV RABBITMQ_CONFIG_FILE "C:\rabbitmq"  
COPY ["rabbitmq.config"," C:/"]  

The config file looks like

[{rabbit, [{loopback_users, []}]}].

Finally we'll start the actual rabbit process as the default action of the container

ENV RABBIT_MQ_HOME "C:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.5"  
CMD "${RABBIT_MQ_HOME}/sbin/rabbitmq-server.bat"  

Now you can log into the management portal using the guest/guest account.

Admin login

It takes quite a while to start up the container and it took me close to 40 years to figure out building the container but it does save me installing rabbitmq on my local machine and makes experimenting with multiple instances pretty jolly easy.

The complete docker file is here:

FROM microsoft/windowsservercore

####### PORTS ########
#Main rabbitmq port
EXPOSE 5672  
#port mapper daemon (epmd)
EXPOSE 4369  
#inet_dist_listen
EXPOSE 35197  
#rabbitmq management console
EXPOSE 15672

#set the home directory for erlang so rabbit can find it easily
ENV ERLANG_HOME "c:\program files\erl8.2\erts-8.2"  
ENV ERLANG_SERVICE_MANAGER_PATH "c:\program files\erl8.2\erts-8.2"

#install chocolatey
RUN @powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"

#install rabbitmq
RUN choco install -y rabbitmq

#set up the path to the config file
ENV RABBITMQ_CONFIG_FILE "C:\rabbitmq"

#copy a config file over
COPY ["rabbitmq.config"," C:/"]

#set the startup command to be rabbit
CMD ["C:/Program Files/RabbitMQ Server/rabbitmq_server-3.6.5/sbin/rabbitmq-server.bat"]

In my next post I'll get around to actually using Rabbit MQ because all the yaks are shaved now... I hope.

C# Wildcards/Discards/Ignororators

There is some great discussion going on about including discard variables in C#, possibly even for the C# 7 timeframe. It is so new that the name for them is still up in the air. In Haskel it is called a wildcard. I think this is a great feature which is found in other languages but isn't well known for people who haven't done funcitonal programming. The C# language has been sneaking into being a bit more functional over the last few releases. There is support for lambdas and there has been a bunch of work on immutability. Let's take a walk through how wildcards works.

Let's say that we have a function which has a number of output paramaters:

void DoSomething(out List<T> list, out int size){}  

Ugh, already I hate this method. I've never liked the out syntax because it is wordy. To use this function you would have to do

List<T> list = null;  
int size = 0;  
DoSomething(out list, out size);  

There is some hope for that syntax in C# 7 with what I would have called inline declaration of out variables but is being called "out variables". The syntax would look like

DoSomething(out List<T> list, out int size);  

This is obviously much nicer and you can read a bit more about it at
https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

However in my code base perhaps I don't care about the size parameter. As it stands right now you still need to declare some variable to hold the size even if it never gets used. For one variable this isn't a huge pain. I've taken to using the underscore to denote that I don't care about some variable.

DoSomething(out List<T> list, out int _);  
//make use of list never reference the _ variable

The issue comes when I have some funciton which takes many parameters I don't care about.

DoSomething(out List<T> list, out int _, out float __, out decimal ___);  
//make use of list never reference the _ variables

This is a huge bit of uglyness because we can't overload the _ variable so we need to create a bunch more variables. It is even more so ugly if we're using tuples and a deconstructing declaration (also part of C# 7). Our funciton could be changed to look like

(List<T>, int, float, decimal) DoSomething() {}

This is now a function which returns a tuple containing everything we previously had as out prameters. Then you can break this tuple up using a deconstructing declaration.

(List<T> list, int size, float fidelity, decimal cost) = DoSomething();

This will break up the tuple into the fields you actually want. Except you don't care about size, fidelity and cost. With a wildcard we can write this as

(List<T> list, int _, float _, decimal _) = DoSomething();

This beauty of this wildcard is that we can use the same wildcard for each field an not worry about them in the least.

I'm really hopeful that this feature will make it to the next release.