This post is the first in a series of posts I plan to do about MassTransit, an open source messaging system written by Dru Sellers (blog) and Chris Patterson. I plan on blogging my observations as I explore both the implementation and the source code. Before I dig into MassTransit specifically, I want first touch on a few introductory items.
What Is Messaging?
Messaging quite simply is a type of notification. In the real-world we deal with this everyday. Consider meeting someone for the first time and you say, "Hello, my name is <your name>." You've published a message. If the person on the end is polite, they will have "subscribed" to your message and choose to publish one back, for example, "Nice to meet you <your name>, my name is <their name>." Another example is someone shouting, "FIRE!" in a crowded theatre. That is a type of message, albeit an important one.
In code, some messages are rigidly defined, such as when an event is raised. Many messages, however are more loosely defined. Consider for example the creation of a string, a log message if you will, that is stored in an in-memory queue.
Can I Benefit From Messaging?
Maybe, maybe not. Once upon a time I worked for a company that offered a CMS product as part of it's product offerings. This system started small but gradually had increased demands in the form of new features clients wanted added. Pretty soon, when you clicked the save button multiple things were happening; a database row would be updated, an email would be sent, a new file would be written, another status file would be updated. These were all executed when the user clicked the button, therefore every action was a blocking action, the server couldn't move on until it was done servicing that particular request. Performance degradation wasn't a problem when only one or two things were happening but as users demanded more features performance suffered, which manifested itself in long page loads.
In this example many of the things the application did after the user clicked the save button could have been moved to an asynchronous processing mechanism. This is where messaging comes in handy, instead of doing all of those tasks in a blocking form you end up instead publishing messages and let some other process come along and do the work for you, asynchronously. This provides for a much quicker and scalable system. For example:
1: public void Save(Entity entity)
2: {
3: EntityRepository.Save(entity);
4:
5: Publish(ShouldSendEmailMessage);
6:
7: Publish(WriteFileMessage);
8:
9: Publish(UpdateStatusFileMessage);
10: }
What Makes MassTransit different?
MassTransit is based on the idea of durability. To explain durability I will point you to the title of an MSDN article by Udi Dahan named "Build Scalable Systems That Handle Failure Without Losing Data". Durable messages means that the message can survive some outside event, such as a server reboot or a process recycling. Imagine my in-memory queue scenario above. Image the queue has 50 messages when the server reboots. Where do the messages go? Since the messages were stored in-memory until they were handled, they are now lost. In other words, these messages were not durable, data was lost.
Poor Man's Durable Messaging
I recently came across an application that chose to write the properties of an email to a database table rather than attempt to send the email real-time (for performance reasons). In this particular instance there was another simple .NET console application that ran every few minutes that would look at the database table and see if there was anything in it, if there was it would pull the records and loop through each one sending an emailing and deleting the record after the email was sent.
Durable, yes. Scalable. No.
Tell Me Why I Need It?
I can hear you now, you're probably thinking, "Hey that database table idea is pretty slick. I'm doing the same thing in my app and it works fine. Why do I need a whole new framework to do this?" The problem that MassTransit seeks to solve is that of scalability. The database table for emails works well if all you have to do is send emails. The more messages you want to handle the more database tables you have to add. Want to add a row to an audit database whenever an action happens, you have set up the database table to hold the information you want the consuming application to handle. In other words for N types of messages you have to do N things; and that's bad when you want to scale.
Why MassTransit and not NServiceBus?
The reasons I chose to explore MassTransit and not NServiceBus are not scientific at all. You may not agree with them, and that is fine, but I'm providing them here so you know why:
- Familiar and Friendly Authors - Dru Seller is one of the nicest guys I met while in Seattle at Alt.NET. If I have questions or comments about MassTransit, I just pick of the phone and give Dru a call. Granted not all of you have that ability, but again, I said these were my reasons. If you are friends with Udi Dahan, I'd strongly suggest you take a look at NServiceBus.
- Familiar Commonality - MassTransit uses and integrates with other frameworks/libraries that I use, most notably it's integration with Windsor/MicroKernel and secondly NHibernate.
- Relatively Small - MassTransit is small, yet powerful, and covers the functionality I need. Being small and young, it is easier for me to go through the project and it's history.