18.11.2014 Views

MassTransit Documentation - Read the Docs

MassTransit Documentation - Read the Docs

MassTransit Documentation - Read the Docs

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>MassTransit</strong> <strong>Documentation</strong><br />

Release 2.0<br />

Chris Patterson, Travis Smith, and Dru Sellers<br />

October 02, 2014


Contents<br />

1 <strong>MassTransit</strong> Installation 3<br />

1.1 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

1.2 How to install . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

1.3 Getting hold of us . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

1.4 How to report bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

2 Configuring <strong>MassTransit</strong> 7<br />

2.1 Show me <strong>the</strong> code! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

2.2 Common Configuration Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

2.3 Common Subscription Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

2.4 Locations in your Application where MT is usually configured . . . . . . . . . . . . . . . . . . . . . 12<br />

2.5 Transport Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2.6 Using <strong>MassTransit</strong> with an IoC Container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

2.7 Common Gotcha’s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

3 How <strong>MassTransit</strong> Works 23<br />

3.1 Key Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.2 When messages are published, how do <strong>the</strong>y get <strong>the</strong>re? . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

3.3 When messages are sent, how do <strong>the</strong>y get <strong>the</strong>re? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

3.4 How to do Request/Response with <strong>MassTransit</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

3.5 Versioning Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

3.6 Inbound Message Processing Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

3.7 How are subscriptions shared? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

3.8 What does <strong>MassTransit</strong> add on top of MSMQ and RabbitMQ? . . . . . . . . . . . . . . . . . . . . . 37<br />

3.9 Defining Sagas using <strong>the</strong> Saga State Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

3.10 Routing of Messages in <strong>MassTransit</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />

3.11 What is <strong>the</strong> Data Bus? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

3.12 What is a Control Bus? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

3.13 Inheritance and Message Class Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

3.14 Companies Using <strong>MassTransit</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

3.15 Serialization Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

3.16 Logging in <strong>MassTransit</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

3.17 Performance Counters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

3.18 Standard Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

3.19 Runtime Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

3.20 Videos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

3.21 What is <strong>MassTransit</strong>? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

3.22 Correlation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

i


3.23 Handling errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />

4 Troubleshooting <strong>MassTransit</strong> 53<br />

4.1 Issues and possible solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

5 Advanced <strong>MassTransit</strong> Concepts 55<br />

5.1 Interop with <strong>MassTransit</strong> (Routing RFC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />

5.2 The Distributor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

6 Samples 59<br />

6.1 Starbucks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

6.2 Heavy Load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

6.3 Open All Night . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

7 <strong>MassTransit</strong> Learning Series 61<br />

7.1 Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

7.2 Creating Your First Consumer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

8 Indices and tables 69<br />

ii


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Contents:<br />

Contents 1


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

2 Contents


CHAPTER 1<br />

<strong>MassTransit</strong> Installation<br />

This section of <strong>the</strong> online docs will explain how to get <strong>MassTransit</strong> into your project. It will also show you were to get<br />

help, how to report bugs, etc. Hopefully, you will find it useful as you explore <strong>the</strong> <strong>MassTransit</strong> framework.<br />

1.1 Prerequisites<br />

<strong>MassTransit</strong> is a .Net framework for C# and will need a .Net runtime to run on.<br />

To work with <strong>MassTransit</strong> you will need to be running on a Windows operating system. The developers of <strong>MassTransit</strong><br />

regulary test on Windows 7 and Windows Server 2008RC2. Though it should still work on Windows Server 2003, as<br />

long as .Net 3.5 sp1 is installed.<br />

Note: People are starting to run <strong>MassTransit</strong> with RabbitMQ on Mono with success.<br />

1.1.1 .Net Framework<br />

Currently <strong>MassTransit</strong> is tested on .Net 3.5 sp1 and .Net 4.0.<br />

1.1.2 Transport Choices<br />

<strong>MassTransit</strong> sits on top of a communication layer like MSMQ, or RabbitMQ. So you will need to have one of those<br />

installed. We currently support:<br />

Loopback<br />

Note: The loopback transport is great for testing. Not so much for production.<br />

ServiceBusFactory.New(sbc =><br />

{<br />

//loopback is configured by default<br />

});<br />

MSMQ<br />

The default queueing platform for Windows<br />

3


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

RabbitMQ<br />

A high volume queueing platform<br />

1.2 How to install<br />

1.2.1 NuGet<br />

The simplest way to install <strong>MassTransit</strong> into your solution/project is to use NuGet.:<br />

nuget Install-Package <strong>MassTransit</strong><br />

However, <strong>the</strong> NuGet packages don’t contain <strong>the</strong> <strong>MassTransit</strong>.RuntimeServices executable and database SQL scripts.<br />

The RuntimeServices system routes messages to multiple subscribers via <strong>the</strong> Subscription Service. If you plan to use<br />

<strong>the</strong> “UseSubscriptionService” feature, <strong>the</strong>n you’ll need to get compile that from source.<br />

1.2.2 Compiling From Source<br />

Lastly, if you want to hack on <strong>MassTransit</strong> or just want to have <strong>the</strong> actual source code you can clone <strong>the</strong> source from<br />

github.com.<br />

To clone <strong>the</strong> repository using git try <strong>the</strong> following:<br />

git clone git://github.com/<strong>MassTransit</strong>/<strong>MassTransit</strong>.git<br />

If you want <strong>the</strong> development branch (where active development happens):<br />

git clone git://github.com/<strong>MassTransit</strong>/<strong>MassTransit</strong>.git<br />

git checkout develop<br />

1.2.3 Build Dependencies<br />

To compile <strong>MassTransit</strong> from source you will need <strong>the</strong> following developer tools installed:<br />

• .Net 4.0 sdk<br />

• ruby v 1.8.7<br />

• gems (rake, albacore)<br />

1.2.4 Compiling<br />

To compile <strong>the</strong> source code, drop to <strong>the</strong> command line and type:<br />

.\build.bat<br />

If you look in <strong>the</strong> .\build_output folder you should see <strong>the</strong> binaries.<br />

4 Chapter 1. <strong>MassTransit</strong> Installation


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

1.3 Getting hold of us<br />

Getting hold of <strong>the</strong> gang behind <strong>MassTransit</strong> is pretty straight forward, we try to help as much as time permits and<br />

have tried to streamline this process as much as possible.<br />

But before you grab hold of us, spend a moment composing your thoughts and formulate your question, <strong>the</strong>re is<br />

nothing as pointless as simply telling us “<strong>MassTransit</strong> does not work for me” with no fur<strong>the</strong>r information to give any<br />

clue to why.<br />

And before you even do that, do a couple of searches to see if your question is already answered, if it has been, you<br />

will get your answer much faster that way.<br />

1.3.1 Mailing List<br />

Getting on or off our mailinglist happens through Google Groups.<br />

http://groups.google.com/group/masstransit-discuss/<br />

If you are going to use <strong>MassTransit</strong>, subscribing to our masstransit-discuss mailing list is probably a very<br />

good idea. This is where most conversation about <strong>MassTransit</strong> is going to happen.<br />

Make sure to pick a good subject line, and if <strong>the</strong> subject of <strong>the</strong> thread changes, please change <strong>the</strong> subject to match,<br />

some of us deal with hundreds of emails per day, after spam-filters, and we need all <strong>the</strong> help we can get to pick <strong>the</strong><br />

interesting ones.<br />

Also, please include <strong>the</strong> diagnostics output generated by <strong>the</strong> config switch<br />

sbc.WriteDiagnosticsToFile("a_file.txt"). This will help jump start a lot of <strong>the</strong> context for<br />

us.<br />

1.3.2 Twitter<br />

The most immediate way to get hold of us, is to shoot a tweet to #mtproj<br />

Our main time zone is Central time in <strong>the</strong> United States.<br />

If you can explain your problem in a clear sentence, twitter is a good way to get quick response. If you do need to<br />

paste log files, config and so on, please use a gist. But because its often not clear because usually <strong>the</strong>re is a great<br />

deal of context to a question we may push you to our mailing list on google groups.<br />

If twitter is all quiet, try <strong>the</strong> mailing list as well, we do have lives, families and jobs to deal with also.<br />

1.3.3 Issues / Tickets<br />

Please do not open an issue on github, unless you have spotted an actual bug in <strong>MassTransit</strong>. Ask on <strong>the</strong> mailing list<br />

first if you are in doubt.<br />

https://github.com/masstransit/masstransit/issues<br />

The reason for this policy, is to avoid <strong>the</strong> bugs being drowned in a pile of sensible suggestions for future enhancements<br />

and call for help from people who forget to check back if <strong>the</strong>y get it and so on.<br />

1.4 How to report bugs<br />

<strong>MassTransit</strong> can be a tricky beast to debug, with a multi-threaded system, trying to track down <strong>the</strong> issue can be a bit<br />

painful.<br />

1.3. Getting hold of us 5


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

So if you run into a bug, please spend a minute collecting <strong>the</strong> right information to help us fix <strong>the</strong> bug.<br />

The most valuable piece of information you can give us, is always give us a failing unit test, if you can’t give us that<br />

<strong>the</strong>n how to reproduce <strong>the</strong> bug in a step by step fashion. O<strong>the</strong>r wise its going to be a lot of back and forth until we can<br />

better understand and get to a failing unit test.<br />

6 Chapter 1. <strong>MassTransit</strong> Installation


CHAPTER 2<br />

Configuring <strong>MassTransit</strong><br />

Now that you have <strong>MassTransit</strong> installed into your project, we need to get it configured so that you can start bringing<br />

<strong>the</strong> awesome! First we have a quickstart which will be followed up with a few configuration examples.<br />

2.1 Show me <strong>the</strong> code!<br />

All right, all right, already. Here you go. Below is a functional setup of <strong>MassTransit</strong>.<br />

1 public class YourMessage { public string Text { get; set; } }<br />

2 public class Program<br />

3 {<br />

4 public static void Main()<br />

5 {<br />

6 Bus.Initialize(sbc =><br />

7 {<br />

8 sbc.UseMsmq();<br />

9 sbc.VerifyMsmqConfiguration();<br />

10 sbc.UseMulticastSubscriptionClient();<br />

11 sbc.ReceiveFrom("msmq://localhost/test_queue");<br />

12 sbc.Subscribe(subs=><br />

13 {<br />

14 subs.Handler(msg=>Console.WriteLine(msg.Text));<br />

15 });<br />

16 });<br />

17<br />

18 Bus.Instance.Publish(new YourMessage{Text = "Hi"});<br />

19 }<br />

20 }<br />

2.1.1 So what is all of this doing?<br />

If we are going to create a messaging system, we need to create a message. YourMessage is a .Net class that will<br />

represent our message. Notice that it’s just a plain C# class (or POCO).<br />

Next up, we need a program to run our code. Here we have a standard issue command line Main method. To setup<br />

<strong>the</strong> bus we start with <strong>the</strong> static class Bus and its Initialize method. This method takes a lambda whose first and<br />

only argument is a class that will let you configure every aspect of <strong>the</strong> bus.<br />

One of your first decisions is going to be “What transport do I want to run on?” Here we have choosen MSMQ<br />

(sbc.UseMsmq()) because its easy to install on a Windows machines (sbc.VerifyMsmqConfiguration()),<br />

will do just that and its most likely what you will use.<br />

7


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

After that we have <strong>the</strong> sbc.UseMulticastSubscriptionClient() this tells <strong>the</strong> bus to pass subscription<br />

information around using PGM over MSMQ giving us a way to talk to all of <strong>the</strong> o<strong>the</strong>r bus instances on <strong>the</strong> network.<br />

This eliminates <strong>the</strong> need for a central control point.<br />

Now we have <strong>the</strong> sbc.ReceiveFrom("msmq://localhost/test_queue) line which tells us to listen for<br />

new messages at <strong>the</strong> local, private, msmq queue ‘test_queue’. So anytime a message is placed into that queue <strong>the</strong><br />

framework will process <strong>the</strong> message and deliver it to any consumers subscribed on <strong>the</strong> bus.<br />

Lastly, in <strong>the</strong> configuration, we have <strong>the</strong> Subscribe lambda, where we have configured a single Handler for our<br />

message which will be activated which each message of type YourMessage and will print to <strong>the</strong> console.<br />

And now we have a bus that is configured and can do things. So now we can grab <strong>the</strong> singleton instance of <strong>the</strong> service<br />

bus and call <strong>the</strong> Publish method on it.<br />

2.1.2 But Singletons are Evil!<br />

If you shudder at <strong>the</strong> thought of a singleton in your code, that’s ok - we have you covered too. Instead of using<br />

Bus.Initialize you can use <strong>the</strong> code below:<br />

1 var bus = ServiceBusFactory.New(sbc =><br />

2 {<br />

3 sbc.UseMsmq();<br />

4 sbc.UseMulticastSubscriptionClient();<br />

5 sbc.ReceiveFrom("msmq://localhost/test_queue");<br />

6 });<br />

2.2 Common Configuration Options<br />

Trying to get multiple applications to talk to each o<strong>the</strong>r is not a simple problem. The biggest difficulty seems to be just<br />

getting everything configured correctly. With over three years of experience in setting up message based systems <strong>the</strong><br />

developers on <strong>MassTransit</strong> have tried <strong>the</strong>ir darndest to make sure that <strong>the</strong> <strong>MassTransit</strong>’s defaults cover <strong>the</strong> majority of<br />

<strong>the</strong> decisions you will have to make while minimizing <strong>the</strong> configuration code you have to deal with. We hope that <strong>the</strong><br />

options are clear and make sense why you need to select <strong>the</strong>m. Below are some of <strong>the</strong> options you have:<br />

2.2.1 Transport Factory Options<br />

ServiceBusFactory.New(sbc =><br />

{<br />

sbc.UseMsmq();<br />

sbc.UseRabbitMq();<br />

});<br />

//if you would like to implement your own.<br />

sbc.AddTransportFactory();<br />

The first decision is what transport are you going to use? RabbitMQ or MSMQ? If you don’t know which one to<br />

choose I suggest reading up on <strong>the</strong> two and see which one works better for your environment.<br />

2.2.2 Basic Options<br />

8 Chapter 2. Configuring <strong>MassTransit</strong>


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

ServiceBusFactory.New(sbc =><br />

{<br />

//transport choice<br />

});<br />

sbc.ReceiveFrom("address");<br />

sbc.UseControlBus();<br />

The next decision we have to make is what address are we going to listen on? Addresses are<br />

in <strong>the</strong> form of a URL and will look like msmq://localhost/queue_name or for RabbitMQ<br />

rabbitmq://localhost/queue_name.<br />

Warning: Each instance must have its own address. For more information see ‘gotchas’<br />

The last concern is, do you want to use a control bus or not. Control Bus<br />

ServiceBusFactory.New(sbc =><br />

{<br />

//transport choice<br />

//address<br />

});<br />

sbc.UseControlBus();<br />

2.2.3 Serializer Options<br />

ServiceBusFactory.New(sbc =><br />

{<br />

//transport choice<br />

//address<br />

//control bus<br />

});<br />

sbc.UseBinarySerializer();<br />

sbc.UseBsonSerializer();<br />

sbc.UseJsonSerializer();<br />

sbc.UseVersionOneXmlSerializer();<br />

sbc.UseXmlSerializer();<br />

//if you would like to implement your own.<br />

sbc.SetDefaultSerializer();<br />

This is mostly optional, because <strong>the</strong> transports will set <strong>the</strong>ir preferred defaults, but if you need to override <strong>the</strong> default<br />

you can using <strong>the</strong>se methods. With <strong>the</strong> SetDefaultSerializer you can provide a custom serializer that you<br />

created.<br />

2.2.4 Bus Tuning Options<br />

ServiceBusFactory.New(sbc =><br />

{<br />

sbc.SetConcurrentConsumerLimit(2);<br />

sbc.SetDefaultTransactionTimeout(5.Minutes());<br />

sbc.AfterConsumingMessage(()=>{});<br />

2.2. Common Configuration Options 9


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

sbc.BeforeConsumingMessage(()=>{}):<br />

sbc.ConfigureEndpoint();<br />

});<br />

These options, aren’t usually needed until you get into production and need to tune <strong>the</strong> behavior of <strong>the</strong> bus.<br />

2.2.5 Turning on Diagnostics<br />

If you want to get a snapshot of how your service bus is configured, you can get a pretty good picture of it by using<br />

<strong>the</strong> method.<br />

var bus = ServiceBusFactory.New(sbc => { /* usual stuff */ });<br />

var probe = bus.Probe();<br />

//you can now inspect <strong>the</strong> probe<br />

//for your convience we also have added a few helper methods.<br />

bus.WriteIntrospectionToFile("a_file.txt"); //great to send with support requests :)<br />

bus.WriteIntrospectionToConsole();<br />

You may also want to inspect a running bus instance remotely. For that you just need to enable remote introspection<br />

like so.<br />

ServiceBusFactory.New(sbc =><br />

{<br />

//<strong>the</strong> usual options<br />

});<br />

sbc.EnableRemoteInstrospection();<br />

You can <strong>the</strong>n use <strong>the</strong> busdriver to query <strong>the</strong> status. using:<br />

busdriver status -uri:<br />

2.2.6 Low Level Config Api<br />

ServiceBusFactory.New(sbc =><br />

{<br />

sbc.AddBusConfigurator<br />

sbc.AddService();<br />

});<br />

If you are using <strong>the</strong>se, <strong>the</strong>n we probably need to talk. This usually means that <strong>the</strong>re is a low level feature we are not<br />

supplying to you. Its totally ok to use <strong>the</strong>se, but <strong>the</strong>y tend to need a lot of parameters and require intimate knowledge<br />

of <strong>MassTransit</strong>.<br />

2.3 Common Subscription Options<br />

<strong>MassTransit</strong> has a lot of ways that you can provide subscription options.<br />

10 Chapter 2. Configuring <strong>MassTransit</strong>


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

2.3.1 Subscription Options During Configuration<br />

ServiceBusFactory.New(sbc =><br />

{<br />

sbc.Subscribe(s=><br />

{<br />

s.Handler(msg => {});<br />

s.Handler((cxt, msg) => {});<br />

s.Instance(yourObject);<br />

s.Consumer(()=> new YourConsumer() );<br />

s.Consumer(consumerFactory);<br />

s.Consumer(consumerType);<br />

s.Consumer();<br />

//for a permanent subscription<br />

s.Consumer()<br />

.Permanent();<br />

s.Saga(sagaRepository);<br />

});<br />

});<br />

//if using an IoC container<br />

//this will scan <strong>the</strong> container and call Consumer(type) on found<br />

//types<br />

s.LoadFrom(container);<br />

Now that we have a transport, an address, and some basic options figured out <strong>the</strong> meat of <strong>the</strong> work is in front of you.<br />

Establishing your subscriptions. As you can see <strong>the</strong>re are a lot of options so I am going to save most of <strong>the</strong> explanation<br />

for <strong>the</strong> next page.<br />

Note: Permanent Subscriptions will NOT be automatically unsubscribed at bus shutdown. See keyideas<br />

2.3.2 Subscription Options With IoC Container<br />

ServiceBusFactory.New(sbc =><br />

{<br />

sbc.Subscribe(s=><br />

{<br />

//if using an IoC container<br />

//this will scan <strong>the</strong> container and call Consumer(type) on found<br />

//types<br />

s.LoadFrom(container);<br />

});<br />

});<br />

Note: Need more notes here<br />

2.3. Common Subscription Options 11


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

2.3.3 Subscription Options During Post Configuration<br />

var bus = ServiceBusFactory.New(sbc => { /* configure */ });<br />

//options<br />

bus.SubscribeConsumer();<br />

bus.SubscribeHandler();<br />

bus.SubscribeInstance();<br />

bus.SubscribeSaga();<br />

Note: Subscriptions established post-configuration are assumed to be transient. If this is to be a permanent subscription,<br />

it needs to be established during configuration.<br />

2.4 Locations in your Application where MT is usually configured<br />

Now that we know how to configure <strong>the</strong> <strong>MassTransit</strong> system, <strong>the</strong> next question is usually where should I do <strong>the</strong><br />

configuration?<br />

The short answer is: Configure it when you are configuring your IoC Container.<br />

2.4.1 Configuring <strong>MassTransit</strong> in a Console Application / Windows Service<br />

I typically do this inside of <strong>the</strong> methods that build up my IoC container and typically I do this in <strong>the</strong> main method.<br />

public class Program<br />

{<br />

public void static main(string[] args)<br />

{<br />

//configure MT<br />

}<br />

}<br />

//execute program logic<br />

2.4.2 Configuring <strong>MassTransit</strong> in a Website<br />

I still typically do this inside of <strong>the</strong> methods that build up my IoC container, but instead of <strong>the</strong> main method it usually<br />

happens in <strong>the</strong> global.asax file.<br />

Note: A lot of our samples show using MT with ano<strong>the</strong>r open source project Topshelf. This is a .Net Windows<br />

Service host, and should not be used with web sites.<br />

public class Global : HttpApplication<br />

{<br />

protected void Application_Start()<br />

{<br />

//configure MT<br />

}<br />

}<br />

//execute program logic<br />

12 Chapter 2. Configuring <strong>MassTransit</strong>


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

2.5 Transport Configuration<br />

Each transport has different configuration options.<br />

2.5.1 Msmq Configuration Options<br />

ServiceBusFactory.New(sbc =><br />

{<br />

sbc.UseMsmq();<br />

sbc.VerifyMsmqConfiguration();<br />

sbc.VerifyMsDtcConfiguration():<br />

});<br />

Crap. I just wiped out <strong>the</strong> msmq and have to rewrite.<br />

UseMsmq() should be obvious. It configures <strong>the</strong> bus to use <strong>the</strong> MSMQ transport.<br />

VerifyMsmqConfiguration() will confirm that MSMQ is correctly installed and fix <strong>the</strong> install by adding missing<br />

components.<br />

VerifyMsDtcConfiguration() will confirm that <strong>the</strong> DTC is setup correctly.<br />

Note: A post on MSMQ and Ports: http://blogs.msdn.com/b/johnbreakwell/archive/2008/04/29/clear-<strong>the</strong>-way-msmqcoming-through.aspx<br />

Note: A post on public vs private queues: http://technet.microsoft.com/en-us/library/cc776346.aspx<br />

Installing MSMQ Step by step (12/21/2011) #. Get to ‘Computer Management’ #. Expand ‘Services and Applications’<br />

#. Expand ‘Message Queuing’ #. Right click on ‘Private Queues’: New > Private Queue #. Enter a ‘Queue Name’ #.<br />

Choose whe<strong>the</strong>r or not you would like it to be ‘Transactional’ or not.<br />

Note: Creating a queue this way will require permission changes. As you will be <strong>the</strong> only person able to administer<br />

<strong>the</strong> queue! STRONGLY suggested that you at this time give <strong>the</strong> Administrator role Full Control over <strong>the</strong> queue.<br />

2.5. Transport Configuration 13


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Permission Role: Consumer Role: Sender<br />

Full Control<br />

• •<br />

Delete<br />

Receive Message<br />

Peek Message<br />

Receive Journal Message<br />

Y<br />

Y<br />

• •<br />

• •<br />

•<br />

•<br />

Get Properties Y Y<br />

Set Porperties<br />

• •<br />

Get Permissions Y Y<br />

Set Permissions<br />

• •<br />

Take Ownership<br />

• •<br />

Send Message Y Y<br />

Special Permissions<br />

• •<br />

2.5.2 RabbitMQ Configuration Options<br />

This is <strong>the</strong> recommended approach for configuring <strong>MassTransit</strong> for use with RabbitMQ.<br />

ServiceBusFactory.New(sbc =><br />

{<br />

sbc.UseRabbitMq(r =><br />

{<br />

r.ConfigureHost(new Uri("rabbitmq://hostname/vhost/queue"), h =><br />

{<br />

h.SetUsername("username");<br />

h.SetPassword("password");<br />

});<br />

});<br />

// o<strong>the</strong>r options<br />

});<br />

UseRabbitMq tells <strong>the</strong> <strong>MassTransit</strong> code to use RabbitMQ as <strong>the</strong> transport. This also sets <strong>the</strong> default serializer to<br />

JSON.<br />

About <strong>the</strong> RabbitMQ routing topology in place with <strong>MassTransit</strong>.<br />

• networks are segregated by vhosts<br />

• we generate an exchange for each queue so that we can do direct sends to <strong>the</strong> queue. it is bound as<br />

a fanout exchange<br />

• for each message published we generate series of exchanges that go from concrete class to each of<br />

its subclass / interfaces <strong>the</strong>se are linked toge<strong>the</strong>r from most specific to least specific. This way if you<br />

14 Chapter 2. Configuring <strong>MassTransit</strong>


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

subscribe to <strong>the</strong> base interface you get all <strong>the</strong> messages. or you can be more selective. all exchanges<br />

in this situation are bound as fanouts.<br />

• <strong>the</strong> subscriber declares his own queue and his queue exchange - he <strong>the</strong>n also declares/binds his<br />

exchange to each of <strong>the</strong> message type exchanges desired<br />

• <strong>the</strong> publisher discovers all of <strong>the</strong> exchanges needed for a given message, binds <strong>the</strong>m all up and <strong>the</strong>n<br />

pushes <strong>the</strong> message into <strong>the</strong> most specific queue letting RabbitMQ do <strong>the</strong> fanout for him. (One<br />

publish, multiple receivers!)<br />

• control queues are exclusive and auto-delete - <strong>the</strong>y go away when you go away and are not shared.<br />

• we also lose <strong>the</strong> routing keys. WIN!<br />

You will need to configure RabbitMQ to support SSL also http://www.rabbitmq.com/ssl.html.<br />

Concurrent Consumers with RabbitMQ<br />

When using concurrent consumers with rabbitmq you need to set both <strong>the</strong> number of concurrent consumers to X and<br />

you need to set <strong>the</strong> prefetch. This is a quick note in <strong>the</strong> docs to remind people of this. A bit of detail is in <strong>the</strong> link<br />

below.<br />

https://groups.google.com/forum/#!topic/masstransit-discuss/-0F7jswXIso<br />

2.5.3 Loopback Configuration Options<br />

ServiceBusFactory.New(sbc =><br />

{<br />

//loopback is <strong>the</strong> default<br />

sbc.ReceiveFrom("loopback://localhost/queue");<br />

});<br />

Note: Great for testing, not great for production.<br />

So <strong>the</strong> loopback uses <strong>the</strong> protocol ‘loopback’ - localhost is <strong>the</strong> machine name and <strong>the</strong>n you can use whatever you want<br />

for <strong>the</strong> ‘queue’ bit as long as each bus instance has a unique one, you should be good to go.<br />

2.6 Using <strong>MassTransit</strong> with an IoC Container<br />

<strong>MassTransit</strong> has been built from <strong>the</strong> beginning with <strong>the</strong> concept of an IoC container being involved. Our support<br />

for using <strong>the</strong>m is quite solid and mature and is most certainly recommended. However with everything else you are<br />

learning trying to figure out just how to get <strong>the</strong> container involved might be overwhelming. Below you will find<br />

prototypical examples of container integration.<br />

2.6.1 StructureMap<br />

public static void main(string[] args)<br />

{<br />

var container = new Container(cfg =><br />

{<br />

// register each consumer<br />

cfg.ForConcreteType();<br />

2.6. Using <strong>MassTransit</strong> with an IoC Container 15


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

});<br />

//or use StructureMap’s excellent scanning capabilities<br />

var bus = ServiceBusFactory.New(sbc =><br />

{<br />

//o<strong>the</strong>r configuration options<br />

});<br />

//this will find all of <strong>the</strong> consumers in <strong>the</strong> container and<br />

//register <strong>the</strong>m with <strong>the</strong> bus.<br />

sbc.Subscribe(x => x.LoadFrom(container));<br />

}<br />

//now we add <strong>the</strong> bus<br />

container.Inject(bus);<br />

Note: We recommend that most of this type of code be placed in an StructureMap Registry<br />

2.6.2 Windsor<br />

public static void main(string[] args)<br />

{<br />

var container = new WindsorContainer();<br />

// register each consumer manually<br />

container.Register(Component.For().LifestyleTransient());<br />

//or use Windsor’s excellent scanning capabilities<br />

container.Register(AllTypes.FromThisAssembly().BasedOn());<br />

var bus = ServiceBusFactory.New(sbc =><br />

{<br />

//o<strong>the</strong>r configuration options<br />

});<br />

//this will find all of <strong>the</strong> consumers in <strong>the</strong> container and<br />

//register <strong>the</strong>m with <strong>the</strong> bus.<br />

sbc.Subscribe(x => x.LoadFrom(container));<br />

}<br />

//now we add <strong>the</strong> bus<br />

container.Register(Component.For().Instance(bus));<br />

Note: We recommend that most of this type of code be placed in an IWindsorInstaller<br />

A POCO handler approach and IWindsorInstaller wrapped could be like <strong>the</strong> following:<br />

public class <strong>MassTransit</strong>Installer : IWindsorInstaller<br />

{<br />

public void Install(IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.ICon<br />

{<br />

var consumerConfig = container.Resolve(); // for configurations, like<br />

var busBatchClose = ServiceBusFactory.New(sbc =><br />

{<br />

16 Chapter 2. Configuring <strong>MassTransit</strong>


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

);<br />

}<br />

sbc.UseMsmq();<br />

sbc.UseMulticastSubscriptionClient();<br />

sbc.ReceiveFrom(consumerConfig.BatchCloseQueue);<br />

sbc.EnableMessageScope();<br />

sbc.Subscribe(x => x.Handler(msg =><br />

{<br />

var handler = container.Resolve();<br />

handler.CloseBatch(msg);<br />

container.Release(handler);<br />

}));<br />

}<br />

}<br />

container.Register(Component.For().Instance(busBatchClose).Named("BatchCloseQueu<br />

container.Release(consumerConfig); // irrelevant for this sample, but we need to release what<br />

2.6.3 AutoFac<br />

public static void main(string[] args)<br />

{<br />

var builder = new ContainerBuilder();<br />

// register each consumer manually<br />

builder.RegisterType().AsSelf();<br />

//or use Autofac’s scanning capabilities -- SomeClass is any class in <strong>the</strong> correct assembly<br />

builder.RegisterAssemblyTypes(typeof(SomeClass).Assembly)<br />

Where(t => t.Implements())<br />

.AsSelf();<br />

//now we add <strong>the</strong> bus<br />

builder.Register(c => ServiceBusFactory.New(sbc =><br />

{<br />

//o<strong>the</strong>r configuration options<br />

//this will find all of <strong>the</strong> consumers in <strong>the</strong> container and<br />

//register <strong>the</strong>m with <strong>the</strong> bus.<br />

sbc.Subscribe(x => x.LoadFrom(c.Resolve()));<br />

})).As()<br />

.SingleInstance();<br />

}<br />

var container = builder.Build();<br />

Note: We recommend that most of this type of code be placed in an Autofac Module<br />

2.6.4 Ninject<br />

public static void main(string[] args)<br />

{<br />

var kernel = new StandardKernel();<br />

2.6. Using <strong>MassTransit</strong> with an IoC Container 17


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

// register each consumer manually<br />

kernel.Bind().ToSelf();<br />

//Dru is currently unaware of any scanning capability<br />

var bus = ServiceBusFactory.New(sbc =><br />

{<br />

//o<strong>the</strong>r configuration options<br />

});<br />

//we have to explicitly configure <strong>the</strong> subscriptions because<br />

//<strong>the</strong> Ninject metadata model is not rich enough.<br />

sbc.Subscribe(subs =><br />

{<br />

subs.Consumer(kernel)<br />

});<br />

}<br />

//now we add <strong>the</strong> bus<br />

kernel.Bind().To(bus);<br />

Note: We recommend that most of this type of code be placed in an Ninject Module<br />

Warning: The Ninject container doesn’t currently support <strong>the</strong> workflow that we can use with <strong>the</strong> o<strong>the</strong>r<br />

containers, and because of that <strong>the</strong> LoadFrom method that our o<strong>the</strong>r container extensions use is not supported.<br />

We filed an issue with <strong>the</strong> Ninject team, and <strong>the</strong> issue was closed with ‘Not going to fix’.<br />

https://github.com/ninject/ninject/issues/35<br />

2.6.5 Unity<br />

{<br />

public static void main(string[] args)<br />

var container = new UnityContainer();<br />

// Lookup <strong>the</strong> types.<br />

// You can scan for all types that implement <strong>the</strong> .All-interface of <strong>the</strong> Consumes-class.<br />

var types = new TypeFinder().FindTypesWhichImplement(typeof(Consumes.All));<br />

foreach (var type in types)<br />

{<br />

var interfaceType = type.GetInterfaces().FirstOrDefault(a=> a == typeof(Consumes<<br />

container.RegisterType(interfaceType, type, new ContainerControlledLifetimeManage<br />

}<br />

// or you can register your types directly.<br />

container.RegisterType<br />

{<br />

sbc.UseRabbitMq(c =><br />

{<br />

// Add configation options if required.<br />

// Default JSON serialization is set by <strong>MassTransit</strong>.<br />

18 Chapter 2. Configuring <strong>MassTransit</strong>


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

}<br />

}));<br />

});<br />

// Configure exchanges.<br />

sbc.ReceiveFrom(receiveQueue);<br />

sbc.Subscribe(s => s.LoadFrom(container));<br />

sbc.SetConcurrentConsumerLimit(concurrentConsumers);<br />

sbc.SetDefaultRetryLimit(retryLimit);<br />

// When using MSMQ as Transport you can choose to verify <strong>the</strong> DTC configuration.<br />

// if (verifyDTCConfiguration)<br />

// sbc.VerifyMsDtcConfiguration();<br />

// Configure logging.<br />

if (enableLogging)<br />

sbc.UseLog4Net();<br />

// No performance counters.<br />

sbc.DisablePerformanceCounters();<br />

2.6.6 Hey! Where’s my container??<br />

Don’t see your container here? Feel free to submit a pull request. You should easily be able to add support by following<br />

<strong>the</strong> o<strong>the</strong>r containers.<br />

2.7 Common Gotcha’s<br />

2.7.1 Trying to share a queue<br />

Each application needs it own address! If you have a website and a console application <strong>the</strong>y will each need<br />

<strong>the</strong>ir own address. For instance <strong>the</strong> website could listen at msmq://localhost/web and <strong>the</strong> console at<br />

msmq://localhost/console.<br />

The reason for this is you are defining <strong>the</strong> ‘receiving’ queue. This is where <strong>the</strong> bus instance will receive its messages.<br />

It would be like sharing a mailbox with your neighbor, some times you get all <strong>the</strong> mail, sometimes <strong>the</strong>y get all <strong>the</strong><br />

mail.<br />

2.7.2 How to do an NServiceBus send only endpoint?<br />

Use <strong>the</strong> IEndpointResolver to get an Endpoint that you can call .Send(msg) on.<br />

2.7.3 How to setup a competing consumer?<br />

need to doc this. ;)<br />

RabbitMQ and Msmq<br />

2.7. Common Gotcha’s 19


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

2.7.4 Where did <strong>the</strong> Batch go?<br />

We removed <strong>the</strong> concept, as it required you to bind to <strong>the</strong> MT dll too tightly in your messages. We don’t yet have a<br />

way to reproduce <strong>the</strong> behavior but you can do this in your application. If you would like to submit an example we<br />

would appreciate it. :)<br />

2.7.5 So, what links two bus instances toge<strong>the</strong>r?<br />

This is a common question. The binding element, really is <strong>the</strong> message contract. If you want message A, <strong>the</strong>n you<br />

subscribe to message A. The internals of MT wires it all toge<strong>the</strong>r.<br />

2.7.6 Why aren’t queue / message priorities supported?<br />

Message Priorities are used to allow a message to jump to <strong>the</strong> front of <strong>the</strong> line. When people ask for this feature <strong>the</strong>y<br />

usually have multiple types of messages all being delivered to <strong>the</strong> same queue. The problem is that each message has<br />

a different SLA (usually <strong>the</strong> one with <strong>the</strong> shorter time window is <strong>the</strong> one getting <strong>the</strong> priority flag). The problem is that<br />

w/o priorities <strong>the</strong> important message gets stuck behind <strong>the</strong> less important/urgent ones.<br />

The solution is to stop sharing a single queue, and instead establish a second queue. In <strong>MassTransit</strong> you would<br />

establish a second instance of IServiceBus and have it subscribe to <strong>the</strong> important/urgent message. Now you have two<br />

queues, one for <strong>the</strong> important things and one for <strong>the</strong> less urgent things. This helps with monitoring queue depths, error<br />

rates, etc. By placing each IServiceBus in its own Topshelf host / process you fur<strong>the</strong>r enhance each bus’s ability to<br />

process messages, and isolate issues / downtime.<br />

<strong>Read</strong>ing<br />

http://www.udidahan.com/2008/01/30/podcast-message-priority-you-arent-gonna-need-it/<br />

http://lostechies.com/jimmybogard/2010/11/18/queues-are-still-queues/<br />

2.7.7 I want to know if ano<strong>the</strong>r bus is subscribed to my message.<br />

So, if you try to program this way, you’re going to have a bad time. ;)<br />

Knowing that you have a subscriber is not <strong>the</strong> concern of your application. It is something <strong>the</strong> system architect should<br />

know, but not <strong>the</strong> application. Most likely, we just need to introduce all of <strong>the</strong> states in our protocol more explicitly,<br />

by using a Saga.<br />

A Sample Saga<br />

//Magnum.StateMachine based saga<br />

public class MySaga :<br />

SagaStateMachine,<br />

ISaga<br />

{<br />

static MySaga()<br />

{<br />

Define(() =><br />

{<br />

Initially(<br />

When(CommandOccured)<br />

.Then(saga => saga.StartTimer()) //pseudo code<br />

.TransitionTo(InProcess));<br />

20 Chapter 2. Configuring <strong>MassTransit</strong>


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

During(InProcess,<br />

When(Timeout)<br />

.TransitionTo(TimedOut),<br />

When(Succeeded)<br />

.TransitionTo(Success),<br />

When(Error)<br />

.TransitionTo(Failed));<br />

}<br />

});<br />

//States<br />

public static State Initial { get; set; }<br />

public static State InProcess { get; set; }<br />

public static State TimedOut { get; set; }<br />

public static State Succeeded { get; set; }<br />

public static State Error { get; set; }<br />

public static State Completed { get; set; }<br />

//Events<br />

public static Event CommandOccured { get; set; }<br />

public static Event Timeout { get; set; }<br />

public static Event Succeeded { get; set; }<br />

public static Event Error { get; set; }<br />

}<br />

//instance data<br />

public virtual Guid CorrelationId {get;set;}<br />

2.7. Common Gotcha’s 21


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

22 Chapter 2. Configuring <strong>MassTransit</strong>


CHAPTER 3<br />

How <strong>MassTransit</strong> Works<br />

3.1 Key Terminology<br />

When getting started using <strong>MassTransit</strong>, it is a good idea to have a handle on <strong>the</strong> terminology used in messaging.<br />

To ensure that you are on <strong>the</strong> right path when looking at a class or interface, here are some of <strong>the</strong> terms used when<br />

working with <strong>MassTransit</strong>.<br />

3.1.1 Messages and Serialization<br />

<strong>MassTransit</strong> is a service bus, and a service bus is designed to move messages. At <strong>the</strong> lowest level, a message is a chunk<br />

of JSON, XML, or even binary data. When using a statically typed language (such as C#), a message is represented<br />

by an instance of a class (or interface) that has relevant properties, each of which can be a value, list, dictionary, or<br />

even ano<strong>the</strong>r nested class.<br />

When using <strong>MassTransit</strong>, messages are sent and received, published and subscribed, as types. The translation (called<br />

serialization) between <strong>the</strong> textual representation of <strong>the</strong> message (which is JSON, XML, etc.) and a type is handled<br />

using a message serializer. The default serialization varies (for MSMQ, <strong>the</strong> framework uses XML by default, for<br />

RabbitMQ JSON is used instead). The default serialization can be changed when a service bus is being configured.<br />

sbc.UseJsonSerializer(); // uses JSON by default<br />

sbc.UseXmlSerializer(); // uses XML by default<br />

sbc.UseBsonSerializer(); // uses BSON (binary JSON) by default<br />

3.1.2 Receiving Messages<br />

At <strong>the</strong> application layer, most users of <strong>MassTransit</strong> are interested in receiving messages. There are several different<br />

receiver types that are supported, providing flexibility it how you interact with <strong>the</strong> framework.<br />

Handlers<br />

The easiest (and, by definition, least flexible) type of receiver is <strong>the</strong> Handler. A handler is any method (including<br />

anonymous and lambda methods) that has a single argument of a message type and a void return type.<br />

void MyMessageHandler(MyMessage message)<br />

{}<br />

When a message is received, <strong>MassTransit</strong> will call <strong>the</strong> method passing <strong>the</strong> message as <strong>the</strong> argument. With a handler,<br />

no special controls are available to manage <strong>the</strong> lifecycle of <strong>the</strong> receiver. Therefore, it is up to <strong>the</strong> application to deal<br />

23


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

with <strong>the</strong> fact that <strong>the</strong> handler may be called simultaneously from multiple threads if more than one message is being<br />

received. If your application is not thread-safe, it is recommended that <strong>the</strong> concurrent consumer limit be set to one in<br />

<strong>the</strong> bus configuration to avoid multithreading issues.<br />

Instances<br />

An Instance receiver is a class instance where <strong>the</strong> class implements one or more Consumes interfaces. Each of <strong>the</strong><br />

Consumes interfaces accepts a generic argument (which must be a reference type) that declares <strong>the</strong> type of message<br />

<strong>the</strong> instance wants to consume. Once an instance is subscribed, as messages of <strong>the</strong> subscribed types are received,<br />

<strong>MassTransit</strong> will call <strong>the</strong> Consume method on <strong>the</strong> class instance passing <strong>the</strong> message as <strong>the</strong> argument.<br />

public class MyClass :<br />

Consumes.All,<br />

Consumes.All<br />

{<br />

public void Consume(MyMessage message)<br />

{}<br />

public void Consume(MyO<strong>the</strong>rMessage message)<br />

{}<br />

}<br />

Consumers<br />

A Consumer is <strong>the</strong> most useful type of receiver and support a number of features that allow proper lifecycle management<br />

of dependencies, as well as multiple message type handling. Consumers are declared using <strong>the</strong> same interfaces<br />

as an instance, however, instead of subscribing an already created instance of <strong>the</strong> class to <strong>the</strong> bus, <strong>the</strong> consumer type<br />

is subscribed along with a consumer factory. As messages are received, <strong>MassTransit</strong> calls <strong>the</strong> consumer factory to get<br />

an instance of <strong>the</strong> consumer and calls <strong>the</strong> Consume method on <strong>the</strong> instance passing <strong>the</strong> message as <strong>the</strong> argument.<br />

By using <strong>the</strong> consumer factory, <strong>MassTransit</strong> allows <strong>the</strong> implementation to handle <strong>the</strong> lifecycle of consumer instances.<br />

Actual implementations vary, and can range from a simple constructor call to create an instance to <strong>the</strong> retrieval of a<br />

consumer and any of <strong>the</strong> consumers dependencies (such as a database session, cache reference, etc.) from an inversion<br />

of control (IoC) container. Since <strong>the</strong> consumer factory returns a handler to <strong>MassTransit</strong>, <strong>the</strong> factory can wrap <strong>the</strong><br />

consumer call with any lifecycle management/synchronization code before and after <strong>the</strong> message is consumed.<br />

Interfaces for Consumers<br />

public class Consumes<br />

{<br />

public interface All : IConsumer<br />

{<br />

void Consume(TMessage message);<br />

}<br />

public interface Selected : All<br />

{<br />

bool Accept(TMessage message);<br />

}<br />

public interface For :<br />

All,<br />

CorrelatedBy<br />

{<br />

24 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

}<br />

}<br />

All<br />

Consumes.All<br />

This interface defines <strong>the</strong> void Consume(TMessage message) method<br />

Selected<br />

Consumes.Selected<br />

This interface defines an additional method allowing to process only selected messages, by implementing <strong>the</strong> bool<br />

Accept(TMessage message) method.<br />

For<br />

Consumes.For<br />

This interface defines how to do a correlated consumer.<br />

Note: Consumers are usually sourced from an IoC container. When <strong>the</strong>y are, <strong>MassTransit</strong> respects your container’s<br />

lifecycle.<br />

Sagas<br />

All of <strong>the</strong> receiver types above are stateless by design, <strong>the</strong> framework makes no effort to correlate multiple messages<br />

to a single receiver. Often it is necessary to orchestrate multiple messages, usually of different types, into a saga<br />

(sometimes called a workflow). A saga is a long-running transaction that is managed at <strong>the</strong> application layer (instead<br />

of, for example, inside of a database or a distributed transaction coordinator). <strong>MassTransit</strong> allows sagas to be declared<br />

as a regular class or as a state machine using a fluent interface.<br />

The key difference for sagas is that <strong>the</strong> framework manages <strong>the</strong> saga instance and correlates messages to <strong>the</strong> proper<br />

saga instance. This correlation is typically done using a CorrelationId, which is an interface (called CorrelatedBy).<br />

Messages correlated an individual saga must be done using a Guid. Sagas may also observe messages that are not<br />

correlated directly to <strong>the</strong> saga instance, but this should be done carefully to avoid potentially matching a message to<br />

hundreds of saga instances which may cause database performance issues.<br />

public class MySaga :<br />

ISaga,<br />

InitiatedBy.All,<br />

Orchestrates.All<br />

{<br />

public Guid CorrelationId { get; set; }<br />

public void Consume(MyInitialMessage message)<br />

{}<br />

public void Consume(MyFollowUpMessage message)<br />

{}<br />

}<br />

3.1. Key Terminology 25


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.1.3 Transports and Endpoints<br />

<strong>MassTransit</strong> is a framework, and being a framework has certain rules. The first of which is known as <strong>the</strong> Hollywood<br />

principle – “Don’t call us, we’ll call you.” Once <strong>the</strong> bus is configured and running, <strong>the</strong> receivers are called by <strong>the</strong><br />

framework as messages are received. There is no need for <strong>the</strong> application to poll a message queue or repeated call a<br />

framework method in a loop.<br />

To initiate <strong>the</strong> calls into your application code, <strong>MassTransit</strong> creates an abstraction on top of <strong>the</strong> messaging platform<br />

(such as MSMQ or RabbitMQ).<br />

Transports<br />

At <strong>the</strong> lowest level, closest to <strong>the</strong> actual messaging platform used, is <strong>the</strong> transport. Transports communicate with <strong>the</strong><br />

actual platform API to send and receive messages. The transport implementation is split into two parts, inbound and<br />

outbound, providing <strong>the</strong> ability to support asymmetric APIs where sending and receiving have different behaviors<br />

and/or addresses.<br />

Endpoints<br />

The endpoint is <strong>the</strong> abstraction used to send messages directly and to receive messages by <strong>the</strong> service bus. It is very<br />

uncommon (and not recommended) for an application to call Receive on an endpoint. Endpoints are referenced by<br />

address and no distinction is made between inbound and outbound at <strong>the</strong> endpoint level.<br />

Address<br />

In <strong>MassTransit</strong>, a URI is used as an address to an endpoint. The elements of <strong>the</strong> URI are used to determine <strong>the</strong> proper<br />

transport, server, port, and queue name of <strong>the</strong> actual endpoint. For example, an MSMQ endpoint on <strong>the</strong> local machine<br />

named “my_queue” would have <strong>the</strong> address shown below.<br />

msmq://localhost/my_queue<br />

A RabbitMQ queue on a remote server may be listed as below.<br />

rabbitmq://user:password@remote_server/my_queue<br />

3.2 When messages are published, how do <strong>the</strong>y get <strong>the</strong>re?<br />

What actually happens when you call bus.Publish(yourMessage)? The process itself is pretty simple, but<br />

it does depend on your transport. The first thing to know is that <strong>MassTransit</strong> has something called an ‘Outbound<br />

Pipeline’. Messages enter into <strong>the</strong> outbound pipeline to be sent to <strong>the</strong> actual transport. Once <strong>the</strong>y hit <strong>the</strong> transport, <strong>the</strong><br />

messages leave your .Net process and enter <strong>the</strong> process of <strong>the</strong> transport infrastructure.<br />

Note: Transports that are currently supported are MSMQ and RabbitMQ. There are also community contributed<br />

ActiveMQ and Azure Service Bus transports. Finally <strong>the</strong>re is a non-production In-Memory Loopback which we use<br />

for testing.<br />

<strong>MassTransit</strong> prefers a dynamic routing model, we do not enforce a static routing model, however it can be achieved<br />

with <strong>the</strong> ‘static routing bits’. What this means is that when you call <strong>the</strong> Subscribe methods, <strong>MassTransit</strong> is going<br />

to setup <strong>the</strong> necessary routing for you.<br />

The ‘necessary’ routing will vary by transport that you use.<br />

26 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Note: We do realize that some prefer a more static approach to this process, so <strong>the</strong>re is an extension to <strong>the</strong> system<br />

to allow this called static routing. You will HAVE to manually set up all subscriptions on ALL endpoints for this to<br />

work. Its a lot of manual monkey work in my opinion, but a scalpel you shall have.<br />

With that out of <strong>the</strong> way lets discuss how <strong>the</strong> transport affects routing.<br />

3.2.1 Multicast MSMQ<br />

Subscription are communicated to each bus through <strong>the</strong> use of multicast MSMQ. This allows us to not have single point<br />

of failure, but it does NOT tollerate all of <strong>the</strong> bus instances going down. This is because <strong>the</strong> subscription information<br />

is being held in memory.<br />

3.2.2 Plain MSMQ<br />

Subscription data is communicated to each bus through an intermediary known as <strong>the</strong> ‘Subscription Service’. The subscription<br />

service is a well known location where each bus sends its subscription requests to, and gets <strong>the</strong> subscription<br />

requests of o<strong>the</strong>rs from.<br />

Publisher<br />

1 // Setup Mass Transit.<br />

2 Bus.Initialize(sbc =><br />

3 {<br />

4 sbc.UseMsmq();<br />

5 sbc.ReceiveFrom("msmq://localhost/BulkProcessing.Web");<br />

6 sbc.UseSubscriptionService("msmq://localhost/mt_subscriptions");<br />

7 // sbc.VerifyMsmqConfiguration(); This doesn’t work on Windows 8.<br />

8 });<br />

9<br />

10 // Send Message<br />

11 var sendContext = new SendContext(message);<br />

12 sendContext.SetMessageId(Guid.NewGuid().ToString());<br />

13 sendContext.SetCorrelationId(Guid.NewGuid().ToString());<br />

14 sendContext.SetExpirationTime(DateTime.Now.AddDays(1));<br />

15<br />

16 Bus.Instance.Publish(message);<br />

Subscriber<br />

1 static void Main(string[] args)<br />

2 {<br />

3 Bus.Initialize(sbc =><br />

4 {<br />

5 sbc.UseMsmq();<br />

6 sbc.ReceiveFrom("msmq://localhost/BulkProcessing.Consumer");<br />

7 sbc.UseSubscriptionService("msmq://localhost/mt_subscriptions");<br />

8 // sbc.VerifyMsmqConfiguration(); This doesn’t work on Windows 8.<br />

9<br />

10 sbc.Subscribe(subs =><br />

11 {<br />

12 subs.Handler(msg => Console.WriteLine(msg.Text));<br />

13 });<br />

3.2. When messages are published, how do <strong>the</strong>y get <strong>the</strong>re? 27


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

14 });<br />

15<br />

16 while (true)<br />

17 {<br />

18 Thread.Sleep(1000);<br />

19 }<br />

20 }<br />

3.2.3 Internal detail of both MSMQ transports<br />

Because MSMQ doesn’t have any routing capabilities, <strong>MassTransit</strong> has built <strong>the</strong>m internal using a construct called a<br />

‘Pipeline.’ This pipeline is configured by <strong>the</strong> local subscription adapter (one for Plain MSMQ and one for Multicast<br />

MSMQ) to add and remove segments to <strong>the</strong> pipeline. When a message comes in it goes through <strong>the</strong> pipeline logic,<br />

and <strong>the</strong>n is sent directly to <strong>the</strong> bus on <strong>the</strong> o<strong>the</strong>r end.<br />

Note: It is <strong>the</strong> subscription service that keeps all of <strong>the</strong> outbound and inbound pipelines, across all of <strong>the</strong> instances,<br />

in order.<br />

3.2.4 RabbitMQ<br />

Because RabbitMQ has a much, much better routing system, instead of trying to redo that work for RabbitMQ, we<br />

instead configure <strong>the</strong> RabbitMQ system’s routing primitives to achieve <strong>the</strong> same thing that we have done in MSMQ<br />

and <strong>the</strong> Outbound/Inbound pipelines.<br />

So a message is routed straight to <strong>the</strong> correct RabbitMQ Exchange. The internal workings of <strong>MassTransit</strong> make sure<br />

to configure RabbitMQ exchanges and bindings to implement <strong>the</strong> <strong>MassTransit</strong> pattern of routing. This means MT can<br />

make one call to RMQ, and let RabbitMQ deal with it from <strong>the</strong>re.<br />

3.3 When messages are sent, how do <strong>the</strong>y get <strong>the</strong>re?<br />

TBD<br />

3.4 How to do Request/Response with <strong>MassTransit</strong><br />

This is a super simple example. I just hacked it up so that we would have something to improve upon later. :)<br />

1 //<strong>the</strong> messages<br />

2 public class BasicRequest :<br />

3 CorrelatedBy<br />

4 {<br />

5 public Guid CorrelationId { get;set; }<br />

6 public string Text { get; set; }<br />

7 }<br />

8 public class BasicResponse :<br />

9 CorrelatedBy<br />

10 {<br />

11 public Guid CorrelationId { get; set; }<br />

12 public string Text { get; set; }<br />

13 }<br />

28 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

1 //<strong>the</strong> responder<br />

2 public class Program<br />

3 {<br />

4 public static void Main()<br />

5 {<br />

6 Bus.Initialize(sbc =><br />

7 {<br />

8 sbc.UseMsmq();<br />

9 sbc.VerifyMsmqConfiguration();<br />

10 sbc.UseMulticastSubscriptionClient();<br />

11 sbc.ReceiveFrom("msmq://localhost/message_responder");<br />

12 sbc.Subscribe(subs=><br />

13 {<br />

14 subs.Handler( (cxt, msg )=><br />

15 {<br />

16 cxt.Respond(new BasicResponse{Text = "RESP"+msg.Text});<br />

17 });<br />

18 });<br />

19 });<br />

20 }<br />

21 }<br />

1 //<strong>the</strong> requester<br />

2 public class Program<br />

3 {<br />

4 public static void Main()<br />

5 {<br />

6 Bus.Initialize(sbc =><br />

7 {<br />

8 sbc.UseMsmq();<br />

9 sbc.VerifyMsmqConfiguration();<br />

10 sbc.UseMulticastSubscriptionClient();<br />

11 sbc.ReceiveFrom("msmq://localhost/message_requestor");<br />

12 });<br />

13<br />

14 Bus.Instance.PublishRequest(new BasicRequest(), x =><br />

15 {<br />

16 x.Handle(message => Console.WriteLine(message.Text));<br />

17 x.SetTimeout(30.Seconds());<br />

18 });<br />

19 }<br />

20 }<br />

Warning: Each instance must have its own address. For more information see ‘gotchas’<br />

So what is going on? The first chunk has <strong>the</strong> messages we are going to work with.<br />

The second chunk shows <strong>the</strong> code to simple echo back <strong>the</strong> request message as a response.<br />

The final chunk shows <strong>the</strong> code to publish <strong>the</strong> request and handle any responses that relate to <strong>the</strong> original request<br />

message. Once any response is received (with <strong>the</strong> same correlation id as <strong>the</strong> original request) <strong>the</strong> remaining handlers<br />

are unsubscribed and <strong>the</strong> request operation completes.<br />

This style of request will block <strong>the</strong> calling thread until ei<strong>the</strong>r a response is received by one of <strong>the</strong> handlers, or <strong>the</strong><br />

timeout period expires. If it expires, a RequestTimeoutException is thrown. If a response handler throws an exception,<br />

that exception is rethrown on <strong>the</strong> thread that sent <strong>the</strong> request (since it is blocked waiting on <strong>the</strong> response anyway).<br />

The request can also be executed asynchronously using <strong>the</strong> Asychronous Programming Model of .NET. By call-<br />

3.4. How to do Request/Response with <strong>MassTransit</strong> 29


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

ing BeginPublishRequest (or <strong>the</strong> endpoint-based BeginSendRequest), an IAsyncResult is returned to <strong>the</strong> caller. The<br />

IAsyncResult could <strong>the</strong>n be passed to whatever framework code is handling <strong>the</strong> asynchronous operation (such as a<br />

BeginWebMethod/EndWebMethod pair or an AsyncController).<br />

Once <strong>the</strong> callback is invoked (or <strong>the</strong> wait handle is signaled), <strong>the</strong> EndRequest method (which is an extension method<br />

off IEndpoint or IServiceBus) must be called to complete <strong>the</strong> request (at this point, any timeout or response handler<br />

exceptions will be thrown).<br />

NOTE: The asynchronous model will create a wait event if requested, but <strong>the</strong> callback style is greatly preferred since<br />

it reduces <strong>the</strong> amount of operating system resources required.<br />

3.5 Versioning Messages<br />

Versioning of messages is going to happen, services evolve and requirements change.<br />

3.5.1 Versioning Existing Message Contracts<br />

Consider a command to fetch and cache a local copy of an image from a remote system.<br />

1 public interface FetchRemoteImage<br />

2 {<br />

3 Guid CommandId { get; }<br />

4 DateTime Timestamp { get; }<br />

5 Uri ImageSource { get; }<br />

6 string LocalCacheKey { get; }<br />

7 }<br />

After <strong>the</strong> initial deployment, a requirement is added to resize <strong>the</strong> image to a maximum dimension before saving it to<br />

<strong>the</strong> cache. The new message contract includes <strong>the</strong> additional property specifying <strong>the</strong> dimension.<br />

1 public interface FetchRemoteImage<br />

2 {<br />

3 Guid CommandId { get; }<br />

4 DateTime Timestamp { get; }<br />

5 Uri ImageSource { get; }<br />

6 string LocalCacheKey { get; }<br />

7 int? MaximumDimension { get; }<br />

8 }<br />

By making <strong>the</strong> _int_ value nullable, commands that are submitted using <strong>the</strong> original contract can still be accepted as<br />

<strong>the</strong> missing value does not break <strong>the</strong> new contract. If <strong>the</strong> value was added as a regular _int_, it would be assigned a<br />

default value of zero, which may not convey <strong>the</strong> right information. String values can also be added as <strong>the</strong>y will be<br />

_null_ if <strong>the</strong> value is not present in <strong>the</strong> serialized message. The consumer just needs to check if <strong>the</strong> value is present<br />

and process it accordingly.<br />

3.5.2 Versioning Existing Events<br />

Consider an event to notify that an image has been cached is now available.<br />

1 public interface RemoteImageCached<br />

2 {<br />

3 Guid EventId { get; }<br />

4 DateTime Timestamp { get; }<br />

5 Guid InitiatingCommandId { get; }<br />

30 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

6 Uri ImageSource { get; }<br />

7 string LocalCacheKey { get; }<br />

8 }<br />

An application will publish <strong>the</strong> event using an implementation of <strong>the</strong> class, as shown below.<br />

1 class RemoteImageCachedEvent :<br />

2 RemoteImageCached<br />

3 {<br />

4 Guid EventId { get; set; }<br />

5 DateTime Timestamp { get; set; }<br />

6 Guid InitiatingCommandId { get; set; }<br />

7 Uri ImageSource { get; set; }<br />

8 string LocalCacheKey { get; set; }<br />

9 }<br />

The class implements <strong>the</strong> event interface, and when published, is delivered to consumers that are subscribed to <strong>the</strong><br />

RemoteImageCached event interface. <strong>MassTransit</strong> dynamically creates a backing class for <strong>the</strong> interface, and populates<br />

<strong>the</strong> properties with <strong>the</strong> values from <strong>the</strong> serialized message.<br />

Note that you cannot dynamically cast <strong>the</strong> RemoteImageCached interface in <strong>the</strong> consumer to <strong>the</strong> RemoteImageCachedEvent,<br />

as <strong>the</strong> actual class is not deserialized. This can be confusing, but is intentional<br />

to prevent classes (and <strong>the</strong> behavior that comes along with it) from being serialized and deserialized.<br />

As <strong>the</strong> event evolves, additional event contracts can be defined that include additional information without modifying<br />

<strong>the</strong> original contract. For example.<br />

1 public interface RemoteImageCachedV2<br />

2 {<br />

3 Guid EventId { get; }<br />

4 DateTime Timestamp { get; }<br />

5 Guid InitiatingCommandId { get; }<br />

6 Uri ImageSource { get; }<br />

7<br />

8 // <strong>the</strong> string is changed from LocalCacheKey to a full URI<br />

9 Uri LocalImageAddress { get; }<br />

10 }<br />

The event class is <strong>the</strong>n modified to include <strong>the</strong> additional property, while still implementing <strong>the</strong> previous interface.<br />

1 class RemoteImageCachedEvent :<br />

2 RemoteImageCached,<br />

3 RemoteImageCachedV2<br />

4 {<br />

5 Guid EventId { get; set; }<br />

6 DateTime Timestamp { get; set; }<br />

7 Guid InitiatingCommandId { get; set; }<br />

8 Uri ImageSource { get; set; }<br />

9 string LocalCacheKey { get; set; }<br />

10 Uri LocalImageAddress { get; set; }<br />

11 }<br />

When <strong>the</strong> event class is published now, both interfaces are available in <strong>the</strong> message. When a consumer subscribes to<br />

one of <strong>the</strong> interfaces, that consumer will receive a copy of <strong>the</strong> message. It is important that both interfaces are not<br />

consumed in <strong>the</strong> same context, as duplicates will be received. If a service is updated, it should use <strong>the</strong> new contract.<br />

Note that ownership of <strong>the</strong> contract belongs to <strong>the</strong> event publisher, not <strong>the</strong> event observer/subscriber.<br />

And contracts should not be shared between event producers as this can create some extensive leakage of<br />

multiple events making it difficult to consume unique events.<br />

3.5. Versioning Messages 31


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

As mentioned above, depending upon <strong>the</strong> interface type subscribed, a dynamic backing class is created by MT.<br />

Therefore, if a consumer subscribes to RemoteImageCached, it is not possible to cast <strong>the</strong> message to RemoteImageCachedV2,<br />

as <strong>the</strong> dynamic implementation does not support that interface.<br />

It should be noted, however, that on <strong>the</strong> IConsumeContext interface, <strong>the</strong>re is a method to TryGetContext<br />

method, which can be used to attempt to deserialize <strong>the</strong> message as type T. So it is possible to<br />

check if <strong>the</strong> message also implements <strong>the</strong> new version of <strong>the</strong> interface and not process as <strong>the</strong> original<br />

version knowing that <strong>the</strong> new version will be processed on <strong>the</strong> same message consumption if both types<br />

are subscribed.<br />

The message is a single message on <strong>the</strong> wire, but <strong>the</strong> available/known types are captured in <strong>the</strong> message headers so<br />

that types can be deserialized from <strong>the</strong> message body.<br />

A lot of flexibility and power, it’s up to <strong>the</strong> application developer to ensure that it is used in a way that ensures<br />

application evolution over time without requiring forklift/switchover upgrades due to breaking message changes.<br />

3.6 Inbound Message Processing Pipeline<br />

There are a lot of moving parts in <strong>MassTransit</strong> to receive a chunk of text from a queue, deserialize <strong>the</strong> text into a<br />

message object, dispatch that message to one or more receivers, and finally acknowledge <strong>the</strong> message on <strong>the</strong> queue.<br />

The diagram below shows <strong>the</strong> path a message takes from <strong>the</strong> transport all <strong>the</strong> way up to <strong>the</strong> receiver.<br />

32 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.6. Inbound Message Processing Pipeline 33


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.7 How are subscriptions shared?<br />

Once a subscription is created on a local bus, this information <strong>the</strong>n needs to be shared between all <strong>the</strong> different bus<br />

instances in your application network.<br />

Say you have a Timeout service. This service runs on a separate bus that is hooked to <strong>the</strong> queue<br />

msmq://localhost/timeout. Whenever your application wants to schedule a timeout, it needs to send a<br />

ScheduleTimeout message to this queue. But in order for your application bus to know this routing path, it<br />

needs to receive this information first.<br />

Though <strong>the</strong> routing data is <strong>the</strong> same, how this information get to all of <strong>the</strong> nodes is different depending on your<br />

transport configuration.<br />

3.7.1 Permanent v.s. Temporary Subscriptions<br />

Subscriptions are what registers <strong>the</strong> intent to consume a given message. The structure of <strong>the</strong> subscription is<br />

Subscription(message_name, address, correlation_id). Permanent subscriptions represent a<br />

subscription that you want to have stay around even if your process is shut down (maybe you are doing an upgrade and<br />

don’t want to miss a message). A temporary subscription is to be used in <strong>the</strong> case where you won’t care if you miss a<br />

message while shut down.<br />

3.7.2 Unsubscribe Token<br />

Any time you call subscribe off of IServiceBus you will get a token back that can be called to unsubscribe <strong>the</strong><br />

subscription.<br />

var subscriptionToken = bus.Subscribe();<br />

//later, when you want to unsubscribe<br />

if(!subscriptionToken())<br />

{<br />

//handle failure condition<br />

}<br />

Note: If you are using a permanent subscription and don’t want unsubscribe don’t call <strong>the</strong> delegate.<br />

If you do call <strong>the</strong> token it will be re-subscribed on start up.<br />

3.7.3 Transport Specific Notes<br />

As said earlier, different transport mechanisms use different subscription distributions. Please take a look below how<br />

your transport layer handles this and to see <strong>the</strong> differences. If your transport layer does not handle this specifically,<br />

you can rely on <strong>the</strong> SubscriptionService<br />

MSMQ Multicast<br />

Warning:<br />

• limited by default to one subnet<br />

• subscriptions do not survive service restarts (no perm subscriptions)<br />

• sensitive to <strong>the</strong> order in which services are brought online<br />

34 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Each bus instance communicates with every o<strong>the</strong>r instance on <strong>the</strong> network through a reliable multicast network protocol.<br />

var bus = ServiceBusFactory.New(sbc =><br />

{<br />

//o<strong>the</strong>r settings<br />

});<br />

sbc.UseMsmq();<br />

sbc.UseMulticastSubscriptionClient(); //turns on multicast<br />

sbc.SetNetwork("YOUR_KEY"); //must be set to cross machines<br />

MSMQ Runtime Services<br />

Each bus instance communicates with every o<strong>the</strong>r instance through an intermediary known as <strong>the</strong> Runtime Services<br />

(specifically <strong>the</strong> Subscription Service).<br />

Note: supports permanent subscriptions<br />

var bus = ServiceBusFactory.New(sbc =><br />

{<br />

//o<strong>the</strong>r settings<br />

});<br />

sbc.UseMsmq();<br />

sbc.UseSubscriptionService("msmq://localhost/my_queue");<br />

RabbitMQ<br />

Each bus instance communicates with a local rabbitmq server. Setting up <strong>the</strong> necessary bindings and queues based on<br />

<strong>MassTransit</strong> conventions. RabbitMQ <strong>the</strong>n syncs all binding information to all nodes in <strong>the</strong> cluster.<br />

Note: supports permanent subscriptions<br />

var bus = ServiceBusFactory.New(sbc =><br />

{<br />

// this is <strong>the</strong> recommended routing strategy, and will call ’sbc.UseRabbitMq()’.<br />

sbc.UseRabbitMqRouting();<br />

});<br />

// more config<br />

3.7.4 Subscription Service<br />

If your transport layer does not provide a transport specific way of sharing subscription information you can use <strong>the</strong><br />

SubscriptionService. In this case subscription coordination depends on a central manager. This manager is<br />

an instance of a SubscriptionService that runs somewhere in your network. Each bus instance <strong>the</strong>n uses a<br />

SubscriptionClient to communicate with this central management and exchanges subscription information.<br />

By default <strong>MassTransit</strong> bundles with <strong>the</strong> MSMQ Runtime Services. This is an MSMQ implementation of <strong>the</strong><br />

SubscriptionService that you can run seperatly from your project. If you do not use <strong>the</strong> MSMQ as a transport<br />

layer you can easily host it yourself.<br />

3.7. How are subscriptions shared? 35


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Hosting a subscription service<br />

The example below creates two ‘application domain’ bus instances and a subscription service. The service bus is<br />

responsible for transporting timeout messages, <strong>the</strong> second is your own awesome application.<br />

//<br />

// setup <strong>the</strong> subscription service<br />

//<br />

var subscriptionBus = ServiceBusFactory.New(sbc =><br />

{<br />

sbc.UseStomp();<br />

sbc.SetConcurrentConsumerLimit(1);<br />

});<br />

sbc.ReceiveFrom("stomp://localhost/mt_subscriptions");<br />

var subscriptionSagas = new InMemorySagaRepository();<br />

var subscriptionClientSagas = new InMemorySagaRepository();<br />

var subscriptionService = new SubscriptionService(subscriptionBus, subscriptionSagas, subscriptionCli<br />

subscriptionService.Start();<br />

//<br />

// setup <strong>the</strong> time out service<br />

//<br />

var timeoutBus = ServiceBusFactory.New(sbc =><br />

{<br />

sbc.UseStomp();<br />

sbc.UseControlBus();<br />

});<br />

sbc.ReceiveFrom("stomp://localhost/mt_timeouts");<br />

sbc.UseSubscriptionService("stomp://localhost/mt_subscriptions");<br />

var timeoutService = new TimeoutService(timeoutBus, new InMemorySagaRepository());<br />

timeoutService.Start();<br />

//<br />

// setup your awesome application bus<br />

//<br />

var bus = ServiceBusFactory.New(sbc =><br />

{<br />

sbc.UseStomp();<br />

sbc.UseControlBus();<br />

sbc.ReceiveFrom("stomp://localhost/your_awesome_application");<br />

sbc.UseSubscriptionService("stomp://localhost/mt_subscriptions");<br />

});<br />

Subscription Client<br />

By stating sbc.UseSubscriptionService("stomp://localhost/mt_subscriptions"); you implicitly<br />

attach a SubscriptionClient to your service bus.<br />

One of <strong>the</strong> first thing this client does, is send a AddSubscriptionClient to <strong>the</strong> SubscriptionService<br />

queue. After that it starts observing subscription modifications and subsequently sends ei<strong>the</strong>r an AddSubscription<br />

or RemoveSubscription messsage. This way updates are propagated to o<strong>the</strong>r nodes in your application network.<br />

36 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

The client also handles <strong>the</strong> SubscriptionRefresh messages it receives from <strong>the</strong> SubscriptionService.<br />

These refresh messages contain <strong>the</strong> subscription information of o<strong>the</strong>r nodes.<br />

3.8 What does <strong>MassTransit</strong> add on top of MSMQ and RabbitMQ?<br />

<strong>MassTransit</strong> is a service bus implementing <strong>the</strong> data bus pattern in a distributed setting. It aims to be a .Net-friendly<br />

abstraction over <strong>the</strong> messaging technologies MSMQ and RabbitMQ. As such it brings a lot of <strong>the</strong> application-specific<br />

logic closer to <strong>the</strong> programmer in an easy-to-configure manner.<br />

Below follows a few of <strong>the</strong> benefits of having <strong>MassTransit</strong> as opposed to having raw access to <strong>the</strong> transport and<br />

building everything directly on top of <strong>the</strong> transport.<br />

3.8.1 Sagas<br />

Sagas is a coordination mechanism in distributed systems that helps with checkpointing. Often Sagas listen for events<br />

or messages and reacts on <strong>the</strong>m by sending fur<strong>the</strong>r messages; what <strong>the</strong> outgoing messages are may depend on contextual<br />

information and questions; such as ‘How long ago was this orchestration started?’<br />

3.8.2 Threaded Consumers<br />

Multiple concurrent receives possible.<br />

3.8.3 Exception Management<br />

If your connection to <strong>the</strong> message broker or queue server goes down, <strong>MassTransit</strong> takes care of trying to reconnect<br />

and deal with those failures, so that you don’t have to.<br />

3.8.4 Retries & Poison Messages<br />

<strong>MassTransit</strong> implements some level of generic exception handling for your consumers: upon complete failure from<br />

your application to deal with a message, it’s moved to an error queue which allows you to inspect <strong>the</strong> message and<br />

requeue it.<br />

If exceptions are thrown from consumers, <strong>MassTransit</strong> by default performs a number of retries by requeueing <strong>the</strong><br />

message, before moving it to <strong>the</strong> error queue.<br />

3.8.5 Transactions<br />

Currently only supported on MSMQ, transactions allow you to join a dequeue operation with a database operation<br />

inside of a transaction and have <strong>the</strong>m execute with ACID properties.<br />

3.8.6 Serialization<br />

How do you format a message over <strong>the</strong> wire? How to handle DateTime (Unspecified, Local, Utc)? How to handle<br />

decimal numbers? <strong>MassTransit</strong> has already thought about it an implemented sensible defaults. <strong>MassTransit</strong> provides<br />

a number of serializers, including BSON, JSON, XML and Binary.<br />

3.8. What does <strong>MassTransit</strong> add on top of MSMQ and RabbitMQ? 37


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.8.7 Headers<br />

Manufacturing a header and using a common envelope format can be a nitty-gritty afair until things stabilize.<br />

<strong>MassTransit</strong> has a documented format that has been tested with billions of messages. Fur<strong>the</strong>rmore, <strong>the</strong> envelope<br />

in use allows buses on o<strong>the</strong>r nodes to reply using <strong>the</strong> source address and perform o<strong>the</strong>r messaging patterns more<br />

easily.<br />

3.8.8 Consumer Lifecycle<br />

<strong>MassTransit</strong> handles <strong>the</strong> creation and disposal of your consumers and doesn’t unsubscribe from a queue/exchange until<br />

all consumers, consuming specifically <strong>the</strong> messages that cause <strong>the</strong> exchange/queue binding, have been unsubscribed.<br />

Also <strong>MassTransit</strong> handles durable and transient subscriptions and <strong>the</strong>ir semantics.<br />

3.8.9 Routing<br />

<strong>MassTransit</strong> implements a subscription service over dumb transports such as MSMQ and intelligent exchange-queue<br />

bindings for smart transports like RabbitMQ. This service communicates in a prioritized band called <strong>the</strong> Control Bus.<br />

3.8.10 Rx integration<br />

Interested in using Reactive Extensions to consume? <strong>MassTransit</strong> gives you this.<br />

3.8.11 Unit Testability<br />

The loopback transport is an in-memory transport that allow you a certain freedom in your integration tests (end-to-end<br />

in a local service).<br />

Fur<strong>the</strong>rmore, <strong>the</strong> TestFactory allows you to easily set up both loopback and real transport-based unit tests for your<br />

consumers.<br />

The code-base of <strong>MassTransit</strong> at https://github.com/<strong>MassTransit</strong>/<strong>MassTransit</strong> contains a large number of well written<br />

tests that service both as verification of functionality and examples for your own unit tests.<br />

3.8.12 Fluent NHibernate Integration<br />

Easily map and register your Sagas with Fluent NHibernate and let <strong>MassTransit</strong> handle <strong>the</strong> transaction boundary of<br />

your Saga, while giving your application easy access to <strong>the</strong> data in <strong>the</strong> saga.<br />

In this case you fur<strong>the</strong>r have <strong>the</strong> option of unit testing your sagas using Fluent NHibernate using an in-memory SQLite<br />

database, which will make your tests run smooth like a mountain river.<br />

3.8.13 Routing & Static Routing<br />

The routing engine is state-of-<strong>the</strong>-art, using <strong>the</strong> Rete Algorithm:http://en.wikipedia.org/wiki/Rete_algorithm with Stact<br />

- <strong>the</strong> .Net actor framework.<br />

If you want to route differently than <strong>the</strong> default per-type routing, <strong>MassTransit</strong> will allow you to do this easily.<br />

38 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.8.14 Hackable<br />

If you feel like extending <strong>MassTransit</strong> with a Transport, Serializer or Service; <strong>the</strong> interfaces have small surface areas<br />

and we’re here to help you (both on github and in <strong>MassTransit</strong>-discuss).<br />

3.8.15 Diagnostics<br />

Using BusDriver, you can diagnose and inspect any bus on <strong>the</strong> network by communicating with it over <strong>the</strong> control bus.<br />

3.8.16 Tracing<br />

Using <strong>the</strong> tracing functionality you can get very detailed timings of when and where things were consumed, how long<br />

<strong>the</strong> receive took, how long <strong>the</strong> consume took and what exceptions were thrown if any.<br />

3.8.17 Monitoring<br />

Using <strong>the</strong> System.Diagnostics namespace and Performance Counters, you can let your operations team know how<br />

your applications are doing; message rates and health status.<br />

3.8.18 Distributor<br />

Using <strong>the</strong> distributor you can create load-based routing, <strong>the</strong>reby maximizing <strong>the</strong> use of your computers.<br />

3.8.19 Timeout Service<br />

You can schedule persistent callbacks/timeouts in your sagas that allow your application to wake up after e.g. a<br />

scheduled SLA limit.<br />

3.8.20 Encryption<br />

Using <strong>the</strong> PreSharedKeyEncryptedMessageSerializer you get pre-shared key Rijndael encryption.<br />

3.9 Defining Sagas using <strong>the</strong> Saga State Machine<br />

Sagas are one of <strong>the</strong> more powerful features in <strong>MassTransit</strong>, allowing complex state and behavior to be defined using<br />

a fluent syntax.<br />

3.9.1 What is a saga?<br />

A saga is a long-lived transaction managed by a coordinator. Sagas are initiated by an event, sagas orchestrates events,<br />

and sagas maintain <strong>the</strong> state of <strong>the</strong> overall transaction. They are designed to manage <strong>the</strong> complexity of a distributed<br />

transaction without locking and immediate consistency. They manage state, and track compensations that are required<br />

if a partial failure occurs.<br />

We didn’t create it, we learned it from:<br />

Cornell paper: http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf<br />

3.9. Defining Sagas using <strong>the</strong> Saga State Machine 39


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Arnon Rotem-Gal-Oz’s book chapter: http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf<br />

3.9.2 Defining a Saga<br />

There are two ways to define a saga using <strong>MassTransit</strong>. The first approach is similar to creating a _consumer_ and<br />

uses interfaces on a class to define <strong>the</strong> messages that can initiate, orchestrate, or be observed by a saga instance. The<br />

second approach creates a state machine from a class definition that defines <strong>the</strong> events, states, and actions that make<br />

up <strong>the</strong> state machine.<br />

3.9.3 Defining a Saga Using <strong>the</strong> State Machine Syntax<br />

To define a saga using <strong>the</strong> state machine, a class that inherits from SagaStateMachine must be created.<br />

1 public class AuctionSaga :<br />

2 SagaStateMachine,<br />

3 ISaga<br />

4 {<br />

5 static AuctionSaga()<br />

6 {<br />

7 Define(() =><br />

8 {<br />

9 // <strong>the</strong> state machine behavior is defined here<br />

10 });<br />

11 }<br />

12 public Guid CorrelationId { get; set; }<br />

13 public IServiceBus Bus { get; set; }<br />

14 }<br />

Shown above is an empty definition of a saga state machine. This is just <strong>the</strong> start, however, as <strong>the</strong>re is much more to be<br />

done. The CorrelationId is <strong>the</strong> Guid assigned to <strong>the</strong> saga when it is created. The _IServiceBus_ property is set before<br />

any methods on <strong>the</strong> saga instance are called, allowing it to be used by <strong>the</strong> event handlers defined in <strong>the</strong> saga.<br />

First, we need to declare <strong>the</strong> valid states for <strong>the</strong> saga. There are two predefined states, _Initial_ and _Completed_,<br />

both of which must be included in <strong>the</strong> saga definition. Any states required by <strong>the</strong> saga also need to be added. Some<br />

example states are shown below.<br />

1 public static State Initial { get; set; }<br />

2 public static State Completed { get; set; }<br />

3 public static State Open { get; set; }<br />

4 public static State Closed { get; set; }<br />

As you see, <strong>the</strong> states are added as public static properties of type _State_. This allows <strong>the</strong> states to be used in code as<br />

properties, instead of relying on strings or o<strong>the</strong>r symbols.<br />

Now, let’s define some events to go along with those states.<br />

1 public static Event Create { get; set; }<br />

2 public static Event Bid { get; set; }<br />

Just like states, events are defined as public static properties on <strong>the</strong> saga class. The generic type specified for <strong>the</strong> event<br />

is <strong>the</strong> message type associated with <strong>the</strong> event. When <strong>the</strong> saga is subscribed to <strong>the</strong> bus, <strong>the</strong> message types for <strong>the</strong> events<br />

are subscribed.<br />

The messages need to be linked to <strong>the</strong> saga instance in some way so <strong>the</strong> proper messages are delivered. The messages<br />

are shown below.<br />

40 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

1 public interface CreateAuction :<br />

2 CorrelatedBy<br />

3 {<br />

4 string Title { get; }<br />

5 string OwnerEmail { get; }<br />

6 decimal OpeningBid { get; }<br />

7 }<br />

When an auction is created, a CreateAuction command is sent to <strong>the</strong> endpoint where <strong>the</strong> saga is subscribed. Since<br />

<strong>the</strong> message is correlated by Guid, <strong>the</strong> CorrelationId of <strong>the</strong> message will be used as <strong>the</strong> CorrelationId of <strong>the</strong> saga by<br />

default (this can be overridden as well).<br />

1 public interface PlaceBid<br />

2 {<br />

3 Guid BidId { get; }<br />

4 Guid AuctionId { get; }<br />

5 decimal MaximumBid { get; }<br />

6 string BidderEmail { get; }<br />

7 }<br />

For <strong>the</strong> bid message, we want to have a unique identifier for <strong>the</strong> bid, so we have a BidId on <strong>the</strong> message. We also need<br />

<strong>the</strong> AuctionId so that <strong>the</strong> message can be delivered to <strong>the</strong> proper saga instance.<br />

Now that we have defined <strong>the</strong> messages that are associated with <strong>the</strong> events defined in <strong>the</strong> saga, we need to specify <strong>the</strong><br />

behavior of how and when those events can be handled. To define <strong>the</strong> behavior, we need to add code to <strong>the</strong> Define call<br />

in <strong>the</strong> static initializer of <strong>the</strong> saga class as shown.<br />

1 static AuctionSaga()<br />

2 {<br />

3 Define(() =><br />

4 {<br />

5 Initially(<br />

6 When(Create));<br />

7 During(Open,<br />

8 When(Bid));<br />

9 });<br />

10 }<br />

The linkage above is pretty simple, but it defines some important characteristics of <strong>the</strong> saga. First, based on <strong>the</strong><br />

definition above, we can see that <strong>the</strong> Create event is only accepted when <strong>the</strong> saga is in <strong>the</strong> _Initial_ state (which is <strong>the</strong><br />

default for newly created saga instances). When an event is handled in <strong>the</strong> initial state, a message for which <strong>the</strong>re is<br />

not an existing saga will create a new saga instance.<br />

A saga instance can only be created by events that appear in <strong>the</strong> Initially section.<br />

_NOTE: Initially() is an alias that is equivalent to specifying During(Initial)._<br />

The During statement defines <strong>the</strong> events that are accepted in <strong>the</strong> state specified. In this case, <strong>the</strong> Bid event is allowed<br />

while <strong>the</strong> saga is in <strong>the</strong> Open State. Since <strong>the</strong> Bid event is not accepted in <strong>the</strong> Initial state, it cannot be used to create<br />

a new saga and will result in an error being logged (which should move <strong>the</strong> message to <strong>the</strong> error queue and publish a<br />

Fault message in response to <strong>the</strong> command).<br />

The Bid event is a special case, however, since <strong>the</strong> message is not correlated by a Guid. In order to deliver <strong>the</strong> message<br />

to <strong>the</strong> proper saga instance, we need to define <strong>the</strong> relationship between <strong>the</strong> message and <strong>the</strong> saga. This is done using<br />

<strong>the</strong> Correlate method, as shown below.<br />

1 static AuctionSaga()<br />

2 {<br />

3 Define(() =><br />

4 {<br />

3.9. Defining Sagas using <strong>the</strong> Saga State Machine 41


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

5 Correlate(Bid)<br />

6 .By((saga,message) => saga.CorrelationId == message.AuctionId);<br />

7 });<br />

8 }<br />

By defining <strong>the</strong> correlation, <strong>the</strong> proper filter expressions are created to load <strong>the</strong> existing saga instance for <strong>the</strong> message.<br />

It is important to realize that <strong>the</strong>se translate directly into LINQ expressions that are passed to <strong>the</strong> saga repository for<br />

loading <strong>the</strong> saga instance, so depending upon your repository implementation you may have to tweak <strong>the</strong> syntax to get<br />

<strong>the</strong> proper result for your database provider. In most cases, a one-to-one relationship as shown above is your best bet.<br />

NOTE: Since <strong>the</strong> CreateAuction message is correlated by Guid, <strong>the</strong> default correlation is used.<br />

Now we need to define some behavior to happen when <strong>the</strong> events occur. We’ve already defined <strong>the</strong> events, we just<br />

need to link up some behavior.<br />

1 static AuctionSaga()<br />

2 {<br />

3 Define(() =><br />

4 {<br />

5 Initially(<br />

6 When(Create)<br />

7 .Then((saga,message) =><br />

8 {<br />

9 saga.OpeningBid = message.OpeningBid;<br />

10 saga.OwnerEmail = message.OwnerEmail;<br />

11 saga.Title = message.Title;<br />

12 })<br />

13 .TransitionTo(Open));<br />

14 });<br />

15 }<br />

16 //<br />

17 public decimal OpeningBid { get; set; }<br />

18 public string OwnerEmail { get; set; }<br />

19 public string Title { get; set; }<br />

Two simple behavior steps have been defined above. The first, an anonymous method called with <strong>the</strong> saga instance and<br />

<strong>the</strong> message, initializes some properties on <strong>the</strong> saga. The second transitions <strong>the</strong> state of <strong>the</strong> saga to Open. Properties<br />

were also added to store <strong>the</strong> auction details that were provided in <strong>the</strong> CreateAuction message.<br />

1 static AuctionSaga()<br />

2 {<br />

3 Define(() =><br />

4 {<br />

5 During(Open,<br />

6 When(Bid)<br />

7 .Call((saga,message) => saga.Handle(message),<br />

8 InCaseOf()<br />

9 .Publish((saga,message,ex) => new OutBid(message.BidId))));<br />

10 });<br />

11 }<br />

12 void Handle(PlaceBid bid)<br />

13 {<br />

14 if(!CurrentBid.HasValue || bid.MaximumBid > CurrentBid)<br />

15 {<br />

16 if(HighBidder != null)<br />

17 {<br />

18 Bus.Publish(new Outbid(HighBidId));<br />

19 }<br />

20 CurrentBid = bid.MaximumBid;<br />

42 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

21 HighBidder = bid.BidderEmail;<br />

22 HighBidId = bid.BidId;<br />

23 }<br />

24 else<br />

25 {<br />

26 throw new UnderBidException();<br />

27 }<br />

28 }<br />

29 //<br />

30 public decimal? CurrentBid { get; set; }<br />

31 public string HighBidder { get; set; }<br />

32 public Guid HighBidId { get; set; }<br />

Above, <strong>the</strong> behavior for accepting a bid is defined. If <strong>the</strong> bid received is higher than <strong>the</strong> current bid, <strong>the</strong> current bid<br />

is updated and <strong>the</strong> high bidder information is stored with <strong>the</strong> saga instance. If <strong>the</strong>re was a high bidder, a message is<br />

published indicating <strong>the</strong> a previous bidder was outbid, allowing actions to be taken such as sending an email to <strong>the</strong><br />

previous high bidder. If <strong>the</strong> new bid is too low, and exception is thrown which is caught by <strong>the</strong> InCaseOf method.<br />

This specifies an exception handler for <strong>the</strong> Call method. Multiple exception handlers can be specified and <strong>the</strong>y are<br />

evaluated in a chain-of-command order where <strong>the</strong> first one that matches <strong>the</strong> type (IsAssignableFrom) is invoked.<br />

The use of <strong>the</strong> Bus property is also demonstrated in <strong>the</strong> Handle method, as it is used to publish <strong>the</strong> outbid message.<br />

3.9.4 Combining Events (think Fork/Join)<br />

In some cases, you may want to create a saga that orchestrates several child sagas or initiate multiple concurrent<br />

commands and continue processing once all of <strong>the</strong> commands have been acknowledged. This can be done using a<br />

clever construct known as Combine(). For example, <strong>the</strong> saga below sends two requests and handles <strong>the</strong> response to<br />

each request separately. An additional Combine statement signifies that <strong>the</strong> two events have completed and triggers a<br />

third event on <strong>the</strong> saga instance.<br />

1 static SupervisorSaga()<br />

2 {<br />

3 Define(() =><br />

4 {<br />

5 Initially(<br />

6 When(Create)<br />

7 .Then((saga,message) =><br />

8 {<br />

9 saga.PostalCode = message.PostalCode;<br />

10 })<br />

11 .Publish((saga,message) => new RequestPostalCodeDetails(saga.PostalCode))<br />

12 .Publish((saga,message) => new RequestGeolocation(saga.PostalCode))<br />

13 .TransitionTo(Waiting));<br />

14<br />

15 During(Waiting,<br />

16 When(PostalCodeDetailsReceived)<br />

17 .Then((saga,message) =><br />

18 {<br />

19 saga.City = message.City;<br />

20 saga.State = message.State;<br />

21 }),<br />

22 When(GeolocationReceived)<br />

23 .Then((saga,message) =><br />

24 {<br />

25 saga.Latitude = message.Latitude;<br />

26 saga.Longitude = message.Longitude;<br />

27 }));<br />

3.9. Defining Sagas using <strong>the</strong> Saga State Machine 43


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

28<br />

29 Combine(PostalCodeDetailsReceived, GeolocationReceived)<br />

30 .Into(<strong>Read</strong>yToProceed, saga => saga.<strong>Read</strong>yFlags);<br />

31<br />

32 During(Waiting,<br />

33 When(<strong>Read</strong>yToProceed)<br />

34 .Then((saga,message) =><br />

35 {<br />

36 saga.Bus.Publish(new PostalCodeDetails(...));<br />

37 })<br />

38 .Complete());<br />

39 });<br />

40 }<br />

41 //<br />

42 public int <strong>Read</strong>yFlags { get; set; }<br />

43 public static Event Create { get; set; }<br />

44 public static Event PostalCodeDetailsReceived { get; set; }<br />

45 public static Event GeolocationReceived { get; set; }<br />

46 public static Event <strong>Read</strong>yToProceed { get; set; }<br />

The combine method declares a set of events that must be triggered before <strong>the</strong> combined event is triggered. In this<br />

case, <strong>the</strong> <strong>Read</strong>yToProceed event is fired when <strong>the</strong> two separate result messages have both been received. The reception<br />

and handling of those messages is done separately as each individual response is received.<br />

This is a pretty simple example of <strong>the</strong> saga, but with this great power comes great responsibility.<br />

(and with that, I’m too tired to continue for now and must rest)<br />

3.9.5 Subscribing to <strong>the</strong> Saga<br />

Once <strong>the</strong> saga has been defined, it is subscribed to <strong>the</strong> bus using <strong>the</strong> Saga subscription method.<br />

1 public class Program<br />

2 {<br />

3 public static void Main()<br />

4 {<br />

5 Bus.Initialize(sbc =><br />

6 {<br />

7 sbc.ReceiveFrom("loopback://localhost/my_saga_bus");<br />

8 sbc.Subscribe(subs =><br />

9 {<br />

10 subs.Saga(new InMemorySagaRepository())<br />

11 .Permanent();<br />

12 });<br />

13 });<br />

14 }<br />

15 }<br />

NOTE: The example above uses an in-memory transport and saga repository, which is not durable. It is shown<br />

for testing purposes only. There is a library for use with NHibernate provided with <strong>MassTransit</strong>, called <strong>MassTransit</strong>.NHibernateIntegration.<br />

It uses FluentNHibernate with NHibernate currently.<br />

3.10 Routing of Messages in <strong>MassTransit</strong><br />

How are messages routed?<br />

44 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.10.1 RabbitMQ Routing Conventionns<br />

As we were building in <strong>the</strong> RabbitMQ support into <strong>MassTransit</strong>, we tried to follow <strong>the</strong> best practices for RabbitMQ<br />

at <strong>the</strong> time. Also, since C# is a strongly typed language, we have tried to make <strong>the</strong> most of that as well. <strong>MassTransit</strong><br />

follows a routing scheme that is based on <strong>the</strong> type of <strong>the</strong> message. All messages published in <strong>MassTransit</strong> are routed<br />

by <strong>the</strong> Message Type. In our case <strong>the</strong> Message Type is going to be <strong>the</strong> .Net type of <strong>the</strong> message class.<br />

Ano<strong>the</strong>r goal was leveraging RabbitMQ for as much of <strong>the</strong> routing logic possible. With MSMQ we had to manage<br />

<strong>the</strong> routing logic ourselves and that added quite a bit of code to <strong>the</strong> project. But with RabbitMQ’s advanced routing<br />

features we hoped we could excise that piece of <strong>the</strong> system.<br />

To achieve that we devised a routing system that leaned on RabbitMQ’s concepts of bindings and exchanges. By<br />

doing so <strong>the</strong> routing logic has been completely moved to RabbitMQ, which has lead to us also working well with<br />

RabbitMQ’s clustering support giving us more HA scenarios as well.<br />

Let’s see <strong>the</strong> story of <strong>the</strong> following message classes<br />

public class PingMessage { ... }<br />

public interface LiteCustomerData { ... }<br />

public class FullCustomerData : LiteCustomerData { ... }<br />

Next we will see what happens when you subscribe to any of <strong>the</strong>se messages.<br />

A note about RabbitMQ. You send to exchanges in RabbitMQ. You receive messages from queues. So how <strong>the</strong> hell<br />

do messages get anywhere? That’s where bindings come into play. You bind a queue to an exchange. That way one<br />

exchange can service multiple queues. This abstracts <strong>the</strong> sending of <strong>the</strong> message from <strong>the</strong> target queue. Pretty cool,<br />

eh? Ok, anyways.<br />

<strong>MassTransit</strong> creates an exchange for each message type. So in <strong>the</strong> three messages above you would see three exchanges.<br />

We also set up a pattern where we bind exchanges to exchanges from <strong>the</strong> most specific to <strong>the</strong> most general.<br />

In this example that would be:<br />

PingMessage<br />

FullCustomerData -> LiteCustomerData<br />

Note: A word about Exchange to Exchange bindings. It is a RabbitMQ only feature. Exchange queue. To limit <strong>the</strong><br />

amount of RabbitMQ churn we have established a directly bound exchange to your queue. This lets you come on and<br />

off <strong>the</strong> network with little impact to <strong>the</strong> flow of messages. 1<br />

If you are leveraging our interface based messaging with a message class like<br />

public class MyMessage : IMessageAA {}<br />

You would see two exchanges ‘MyMessage’ and ‘IMessageAA’. You will also see an exchange to exchange binding<br />

from ‘MyMessage’ to ‘IMessageAA’ (from concrete to <strong>the</strong> interface). If you subscribet to <strong>the</strong> concrete type you get a<br />

binding to ‘MyMessage’ if you subscribe to ‘IMessageAA’ you get a binding to ‘IMessageAA’.<br />

NOTE: Why are we doing this?<br />

3.11 What is <strong>the</strong> Data Bus?<br />

The data bus is <strong>the</strong> instance of IServiceBus that you will work with day in and day out. It is <strong>the</strong> instance that listens<br />

at msmq://localhost/servicea that you configured at start up. This is typically <strong>the</strong> one you want set to<br />

transactional queues and want to be careful about just randomly purging.<br />

1 http://blog.springsource.com/2011/04/01/routing-topologies-for-performance-and-scalability-with-rabbitmq/<br />

3.11. What is <strong>the</strong> Data Bus? 45


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.12 What is a Control Bus?<br />

Warning: The existing ControlBus configuration method is being removed. Please read below for <strong>the</strong> replacement<br />

The idea of <strong>the</strong> control bus is one that responds to control messages. That is to say, not <strong>the</strong> messages and events that<br />

are running your business. It is recommended that <strong>the</strong> control messages also be sent on a separate Endpoint or in<br />

our case a different RabbitMQ Queue or MSMQ Queue.<br />

By setting <strong>the</strong> control bus up on a different Endpoint control messages can’t get blocked by data messages and vice<br />

versa. We use this to do various things such as reload configuration data, clear caches, or check on <strong>the</strong> health of our<br />

distributed services.<br />

Note: We recommend doing a purge before startup of <strong>the</strong> queue to make sure old/stale control messages are not<br />

consumed.<br />

1 var controlBus = ServiceBusfactory.New(sbc =><br />

2 {<br />

3 sbc.SetPurgeOnStartup(true);<br />

4<br />

5 //o<strong>the</strong>r configuration code<br />

6 });<br />

Inspiration:<br />

http://www.eaipatterns.com/ControlBus.html<br />

3.13 Inheritance and Message Class Design<br />

That said, I would advise you to think about <strong>the</strong> following things:<br />

1. Interface-based inheritance is OK<br />

2. Class-based inheritance is to be approached with caution<br />

3. Composing messages toge<strong>the</strong>r ends up pushing us into content-based routing which is something we don’t<br />

recommend<br />

4. Message Design is not OO Design (A message is just state, no behavior) There is a greater focus on interop and<br />

contract design.<br />

5. As messages are more about contracts, we suggest subscribing to interfaces that way you can easily evolve <strong>the</strong><br />

implementation of <strong>the</strong> message.<br />

6. A big base class may cause pain down <strong>the</strong> road as each change will have a larger ripple. This can be especially<br />

bad when you need to support multiple versions.<br />

3.14 Companies Using <strong>MassTransit</strong><br />

3.14.1 Company Name<br />

How are you using it. Transport Choice O<strong>the</strong>r Comments<br />

46 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.14.2 Academy Mortgage Corporation<br />

3.14.3 Federal Home Loan Bank of Topeka<br />

Using <strong>MassTransit</strong> to support <strong>the</strong> internal integration of bank processes.<br />

Using: MSMQ<br />

3.15 Serialization Options<br />

Using NHibernate terminology<br />

3.16 Logging in <strong>MassTransit</strong><br />

Logging in <strong>MassTransit</strong> is done with <strong>the</strong> de facto logging tool ‘log4net.’ This tool was chosen for its many<br />

years of battle hardened code and ease of use. You can find out more about log4net and its configuration at<br />

http://logging.apache.org/log4net<br />

Like NHibernate’s ‘NHibernate.SQL’ where all of NHibernate’s generated sql is logged, <strong>MassTransit</strong> has a log named<br />

‘<strong>MassTransit</strong>.Messages’ where all of <strong>the</strong> message traffic is logged. This logging looks like:<br />

RECV:{Address}:{Message Id}:{Message Type Name} SEND:{Address}:{Message Name}<br />

3.16.1 Logging with <strong>MassTransit</strong>.Log4Net<br />

First you need to get <strong>the</strong> latest <strong>MassTransit</strong>.Log4Net from NuGet or download it from<br />

https://nuget.org/packages/<strong>MassTransit</strong>.Log4Net.<br />

Then add logging to your service bus initialization.<br />

using <strong>MassTransit</strong>.Log4NetIntegration;<br />

XmlConfigurator.Configure();<br />

ServiceBus = ServiceBusFactory.New(sbc =><br />

{<br />

/* usual stuff */<br />

sbc.UseLog4Net();<br />

});<br />

The easiest way to configure logging is through <strong>the</strong> web.config or app.config.<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

3.15. Serialization Options 47


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

This will log to <strong>MassTransit</strong>.log in <strong>the</strong> root folder. There are a lot more configuration options explained at<br />

http://logging.apache.org/log4net/release/manual/configuration.html.<br />

3.16.2 Logging with <strong>MassTransit</strong>.NLog<br />

First you need to get <strong>the</strong> latest <strong>MassTransit</strong>.NLog for NuGet or download it from<br />

https://nuget.org/packages/<strong>MassTransit</strong>.NLog<br />

Then add logging to your service bus initialization<br />

The easiest way to configure logging is through ???? (thoughs for <strong>the</strong> NLog community?)<br />

3.17 Performance Counters<br />

Masstransit has support for updating Windows performance counters. Chris has a post introducing <strong>the</strong>m - Performance<br />

Counters Added to <strong>MassTransit</strong>. http://lostechies.com/chrispatterson/2009/10/14/performance-countersadded-to-masstransit/<br />

3.17.1 User Permissions<br />

The user running your mass transit enabled application will need access to update <strong>the</strong> performance counters.<br />

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib<br />

If Masstransit does not detect <strong>the</strong> performance counters it wishes to write to it will attempt to create <strong>the</strong>m. If <strong>the</strong> user<br />

credentials do not have administrative access likely <strong>the</strong>y will not have <strong>the</strong> ability to create <strong>the</strong> performance counters<br />

and errors will be logged.<br />

3.17.2 Windows Installer<br />

When deploying your mass transit enabled application it is possible to have Windows Installer create your performance<br />

counters for you. Below is Xml used by Wix 3.0 to define <strong>the</strong> Masstransit performance counters.<br />

<br />

...<br />

<br />


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Threads” Help=”The current number of threads receiving messages.” Type=”numberOfItems32”/><br />

<br />

<br />

<br />

<br />

<br />

<br />

3.18 Standard Services<br />

Note: needs to be cleaned up<br />

Installing MSMQ<br />

run <strong>the</strong> install_msmq.bat run <strong>the</strong> server_install_msmq.bat You can also do this form C# code when configuring <strong>the</strong><br />

bus. Subscription Service<br />

• Installation<br />

MSMQ should be installed (see Installing MSMQ) By default this service is set to run in-memory store Run <strong>the</strong><br />

create_[servicename]_queue.vbs Go to <strong>the</strong> queues Properties>Security tab and ensure to give ?local administrators?<br />

Full Access. By default MSMQ only gives YOU access. Leave all o<strong>the</strong>r permissions at default. Copy <strong>the</strong> files<br />

wherever you want <strong>the</strong>m run ?SubscriptionServiceHost.exe /install? Health Service<br />

• Installation<br />

MSMQ should be installed (see Installing MSMQ) By default this service is set to run in-memory store Run <strong>the</strong><br />

create_[servicename]_queue.vbs Go to <strong>the</strong> queues Properties>Security tab and ensure to give ?local administrators?<br />

Full Access. By default MSMQ only gives YOU access. Leave all o<strong>the</strong>r permissions at default. Copy <strong>the</strong> files<br />

wherever you want <strong>the</strong>m run ?SubscriptionServiceHost.exe /install? Timeout Service<br />

• Installation<br />

MSMQ should be installed (see Installing MSMQ) By default this service is set to run in-memory store Run <strong>the</strong><br />

create_[servicename]_queue.vbs Go to <strong>the</strong> queues Properties>Security tab and ensure to give ?local administrators?<br />

Full Access. By default MSMQ only gives YOU access. Leave all o<strong>the</strong>r permissions at default. Copy <strong>the</strong> files<br />

wherever you want <strong>the</strong>m run ?SubscriptionServiceHost.exe /install? Health, and Subscription Services can be as one<br />

?Runtime? services instead of distinct services<br />

MSMQ should be installed The service will attempt to create any missing queues Copy <strong>the</strong> files to where you want<br />

<strong>the</strong>m Edit <strong>the</strong> <strong>MassTransit</strong>.RuntimeServices.exe.config to point to <strong>the</strong> right connection string and subscriptions queue<br />

run ?<strong>MassTransit</strong>.RuntimeServices.exe /install? To set <strong>the</strong>se services up to run with a persistant (MSSSQL) store<br />

3.18. Standard Services 49


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

A SQL Server 2008 database installed. If it is not on <strong>the</strong> local drive, please follow <strong>the</strong> setup considerations below.<br />

Mass Transit will try to install to your local database. If you need it to install to a different one, please edit <strong>the</strong><br />

?SET INSTANCE=(local)? in <strong>the</strong> _install.cmd file and set that to a database instance you would like to use. Ensure<br />

you have permission to create databases on that instance. Open <strong>the</strong> servicename.castle.xml in an editor. Find <strong>the</strong><br />

hibernate.connection.connection_string in <strong>the</strong> facilities section of <strong>the</strong> file. Edit <strong>the</strong> server location. If you would like<br />

to set a more secure password for <strong>the</strong> login, please update it in <strong>the</strong> SQLScriptsCreateUserAccountLoginDDL.sql and<br />

also in <strong>the</strong> hibernate connection string from <strong>the</strong> step before this.<br />

3.19 Runtime Services<br />

The <strong>MassTransit</strong> framework also comes with several services which can be run to provide additional functionality, as<br />

well as examples of how to build services that ei<strong>the</strong>r extend bus behavior or provide a general service. These services<br />

are:<br />

3.19.1 Subscription Service<br />

Note: This is only needed for MSMQ or o<strong>the</strong>r transports that have no routing capabilities<br />

Because MSMQ has anemic routing capabilities <strong>MassTransit</strong> originally shipped with a central subscription registry<br />

that all of <strong>the</strong> busses could listen to, to learn when a new ?subscription? would come online. As of 2.0 <strong>the</strong> Msmq-<br />

MulticastSubscription manager provides similar functionality while removing <strong>the</strong> need for a single point of failure.<br />

For users of RabbitMQ this service is not needed as <strong>the</strong> RabbitMQ approach leverages its excellent message routing<br />

capabilities.<br />

Warning: The MsmqMulticastSubscription should not be considered for production yet. I doesn’t persist to disk<br />

so a restart can mean a wipeout of subscriptions. If we had a way to write <strong>the</strong>se to disk this would be a more robust<br />

option. We use it mostly for demo / unit testing.<br />

3.19.2 Timeout Service<br />

This service provide an easy event based way to register timeouts for your sagas. These timeouts are persisted to disk<br />

and will survive restart.<br />

3.19.3 Health Service<br />

Attempts to track all known endpoints and monitor <strong>the</strong>ir status for up/down. Currently is very remedial.<br />

3.20 Videos<br />

There are several videos of presentations featuring <strong>MassTransit</strong>.<br />

Event Driven Architecture Presented at <strong>the</strong> North Dallas .NET User Group in February, 2010 by Chris Patterson.<br />

http://www.drowningintechnicaldebt.com/ShawnWeisfeld/archive/2010/02/04/event-driven-architecture-by-chrispatterson-north-dallas-.net.aspx<br />

O<strong>the</strong>rs I?m sure, I just need to find <strong>the</strong>m and link <strong>the</strong>m here.<br />

50 Chapter 3. How <strong>MassTransit</strong> Works


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

3.21 What is <strong>MassTransit</strong>?<br />

<strong>MassTransit</strong> (MT) is a framework for creating distributed applications on <strong>the</strong> .Net platform. MT provides <strong>the</strong> ability<br />

to subscribe to messages by type and <strong>the</strong>n connect different processing nodes through message subscriptions building<br />

a cohesive mesh of services.<br />

3.21.1 A bit of <strong>the</strong> back story?<br />

We are often asked why <strong>MassTransit</strong> was created, well here’s <strong>the</strong> story. :)<br />

In 2007, Chris Patterson (@phatboyg) and Dru Sellers (@drusellers) met, for what Dru thinks is <strong>the</strong> first time, at <strong>the</strong><br />

first Alt.Net conference. It was at this conference that Chris and Dru not only realized that <strong>the</strong>y had a lot of <strong>the</strong> same<br />

problems that <strong>the</strong>y needed to solve, but also how much <strong>the</strong> standard tooling being provided by Microsoft just didn’t<br />

fit <strong>the</strong>ir needs. Surrounded by <strong>the</strong> best and brightest in .Net <strong>the</strong> energy to build better tooling that supported testable<br />

processes, was aware of <strong>the</strong> latest advances in tooling, libraries, and coding practices; <strong>the</strong>y decided that a better option<br />

must exist. After searching <strong>the</strong> .Net ecosystem for a tool that would help <strong>the</strong>m achieve goals, <strong>the</strong> only real option<br />

was <strong>the</strong> venerable NServiceBus (NSB). After reviewing NSB, it was determined that <strong>the</strong> only real IoC support was<br />

for Spring.Net, and that <strong>the</strong> NSB wasn’t quite ready for external contributors to come in. Therefore, <strong>the</strong>y decided to<br />

embark on <strong>the</strong> quixotic trek of building <strong>the</strong>ir own service bus.<br />

Initially <strong>the</strong> goals were as much about learning about distributed message based systems, as well as building something<br />

both of <strong>the</strong>ir companies could use. The first commit was pushed to GoogleCode on 12/26/2007, and shortly <strong>the</strong>re after<br />

both Dru and Chris went to production with MT and both of <strong>the</strong>ir companies have had success in getting value out of<br />

<strong>the</strong>ir efforts.<br />

Now 4 years later, Chris and Dru continue to push forward on <strong>the</strong>ir Journey, and have been joined by Travis Smith<br />

(@legomaster). The near future should bring much for <strong>the</strong> MT community as RabbitMQ and ActiveMQ support take<br />

front center with <strong>the</strong> quest for Mono support becoming increasingly important.<br />

3.21.2 The Philosophy<br />

First and foremost, we are not an Enterprise Service Bus (ESB). While MT is used in several enterprises its not a swiss<br />

army knife, we are not driven by sales to be a million features wide, and an inch deep. We focus on a few key concepts<br />

and try to make <strong>the</strong>m as robust as possible.<br />

We don’t do doodleware, you won’t find a designer, we are all about <strong>the</strong> keyboard samurais, <strong>the</strong> true in-<strong>the</strong>-trenches<br />

coder. That’s who we are, and those are our friends. If you want to draw, use a whiteboard.<br />

We don’t do FTP->WS-deathstar->BS (not that you can’t, its just not in <strong>the</strong> box). We focus on <strong>the</strong> experience of using<br />

one transport in a given environment, and we try to make it as smooth as possible.<br />

MT is built to be used inside <strong>the</strong> firewall, its not built to be used as a means to communicate with external vendors (it<br />

can be, again its just not in <strong>the</strong> box), its meant to be used for getting your corporate services talking to each o<strong>the</strong>r and<br />

making building internal software easier.<br />

3.22 Correlation<br />

In <strong>MassTransit</strong> we can mark a message as correlated by implementing <strong>the</strong> interface<br />

public interface CorrelatedBy<br />

{<br />

TKey CorrelationId { get; }<br />

}<br />

3.21. What is <strong>MassTransit</strong>? 51


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Ok, that?s great, but what does it mean to be correlated? In short it means that this message is a part of a larger story.<br />

For instance, you may have a message that says ?New Order (Item:Hammers; Qty:22; OrderNumber:45)? and <strong>the</strong>re<br />

may be ano<strong>the</strong>r message that is a response to that message that says ?Order Allocated(OrderNumber:45)?. In this case<br />

<strong>the</strong> order number is acting as your correlation id, it ties <strong>the</strong> messages toge<strong>the</strong>r.<br />

NOTE: Since most transactions in a system will ultimately be logged and wide-scale correlation is likely, it is recommended<br />

to use a Guid type. The Magnum library has a CombGuid that is clustered-index friendly for SQL Server,<br />

making it as efficient to insert as an integer/bigint key. Just use CombGuid.Generate() to get a new one and be happy.<br />

Note, this is <strong>the</strong> same algorithm that NHibernate uses for guid.comb primary keys.<br />

Also, sagas are always correlated with Guids, so any messages that will interact with <strong>the</strong> saga should use a Guid<br />

correlationId.<br />

3.23 Handling errors<br />

Handling errors in your consumers is quite easy.<br />

Let’s suppose that you have a message containing a some data that needs to be saved to a database. In <strong>the</strong> event of a<br />

failure to save that data, that code throws an exception say, SqlErrorException or someo<strong>the</strong>r monkey business.<br />

What do you do?<br />

The easiest thing is to just let <strong>the</strong> exception bubble out of your consumer method and <strong>MassTransit</strong> will automatically<br />

catch <strong>the</strong> exception for you, and <strong>the</strong>n, by default, will retry <strong>the</strong> message 5 times for you. After 5 attempts it will move<br />

<strong>the</strong> error to <strong>the</strong> ‘error queue’. From <strong>the</strong>re you will need to inspect <strong>the</strong> message in <strong>the</strong> error queue and decide what you<br />

need to do.<br />

52 Chapter 3. How <strong>MassTransit</strong> Works


CHAPTER 4<br />

Troubleshooting <strong>MassTransit</strong><br />

4.1 Issues and possible solutions<br />

• Messages are not being received by bus instances<br />

4.1.1 Possible solutions<br />

1) Assuming bus instances are configured to use MSMQ transport and are using multicast. Machines with multiple<br />

NICs (ei<strong>the</strong>r hardware or virtual devices) need to have MSMQ binding configured in <strong>the</strong> following way :<br />

At <strong>the</strong> registry key [HKEY_LOCAL_MACHINESOFTWAREMicrosoftMSMQParameters]<br />

• Add new string value with name “BindInterfaceIP”. As a value enter machine’s IP address<br />

• Add new string value with name “MulticastBindIP”. As a value enter machine’s IP address<br />

• Restart MSMQ service<br />

At <strong>the</strong> end <strong>the</strong> registry entries should look like this :<br />

References<br />

• http://support.microsoft.com/kb/974813<br />

• http://technet.microsoft.com/en-us/library/cc756156(v=ws.10).aspx<br />

Confirmed to work in Windows Vista SP2 and Windows Server 2008 R2 environments<br />

53


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

54 Chapter 4. Troubleshooting <strong>MassTransit</strong>


CHAPTER 5<br />

Advanced <strong>MassTransit</strong> Concepts<br />

Advanced notes.<br />

5.1 Interop with <strong>MassTransit</strong> (Routing RFC)<br />

<strong>MassTransit</strong>’s serializers do <strong>the</strong> main work of formatting <strong>the</strong> data that goes over <strong>the</strong> wire. Below is <strong>the</strong> message format<br />

that everything is mapped to/from:<br />

string RequestId<br />

string ConversationId<br />

string CorrelationId<br />

string DestinationAddress<br />

DateTime? ExpirationTime<br />

string FaultAddress<br />

IDictionary Headers<br />

object Message<br />

string MessageId<br />

IList MessageType<br />

string Network<br />

string ResponseAddress<br />

int RetryCount<br />

string SourceAddress<br />

This is a minimal message:<br />

Which translates to <strong>the</strong>se required properties:<br />

• message<br />

• messageType<br />

• destinationAddress<br />

MessageType is a list of urns. See MessageUrnSpecs for <strong>the</strong> format. Informally, it’s like this:<br />

urn:message:NAMESPACE1.NAMESPACE2:TYPE<br />

‘retryCount’, ‘headers’ will be defaulted.<br />

55


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

5.2 The Distributor<br />

5.2.1 What is <strong>the</strong> distributor?<br />

The Distributor in <strong>MassTransit</strong> provides <strong>the</strong> ability to allocate work across multiple workers when using MSMQ. This<br />

would be similar to using completing consumers with o<strong>the</strong>r transports, such as RabbitMQ. If you are not using MSMQ,<br />

<strong>the</strong> distributor is not suggested for use.<br />

The distributor works by consuming <strong>the</strong> message (TMessage) that <strong>the</strong> workers will be consuming, checking to see<br />

if a worker is free, <strong>the</strong>n sending a Distributed message directly to <strong>the</strong> worker. This is done within<br />

<strong>MassTransit</strong>, so you are just required to register your configuration and <strong>the</strong> rest is taken managed by <strong>MassTransit</strong>.<br />

5.2.2 How do I set up <strong>the</strong> producer?<br />

When configuring <strong>the</strong> bus, use UseDistributorFor() per <strong>the</strong> example below...<br />

Replace MyMessageType with <strong>the</strong> message you want distributed across your workers.<br />

5.2.3 How do I set up workers?<br />

The configuration for workers is similar, ImplementDistributorWorker(consumerFactory). The consumer<br />

factory should return an action for consuming message, if apporiate.<br />

5.2.4 How can I alter <strong>the</strong> scheduling algo in use? Can I alter it at all?<br />

The default scheduling is not configuratable, but implementing a IWorkerSelectionStrategy interface and registering it<br />

with <strong>the</strong> Producer will allow you to use your own<br />

56 Chapter 5. Advanced <strong>MassTransit</strong> Concepts


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

5.2.5 Does <strong>the</strong> distributor only schedule inside of a single bus, or does it work<br />

across <strong>the</strong> network?<br />

Distributed messages are intercepted at <strong>the</strong> source bus, and distributed to <strong>the</strong> workers from <strong>the</strong>re.<br />

5.2.6 Can I use <strong>the</strong> distributor as a router inside of a service bus that would serve<br />

similar to a gateway/message broker?<br />

In <strong>the</strong>ory yes. Content based routing can be supported with <strong>the</strong> IWorkerSelectionStrategy, however, we suggest that<br />

implementors consider not using this for content based routing.<br />

5.2. The Distributor 57


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

58 Chapter 5. Advanced <strong>MassTransit</strong> Concepts


CHAPTER 6<br />

Samples<br />

6.1 Starbucks<br />

This sample is based on: http://www.enterpriseintegrationpatterns.com/ramblings/18_starbucks.html<br />

Note: Do not run both <strong>the</strong> pre-built services and <strong>the</strong> subscription manager GUI at <strong>the</strong> same time. The GUI has <strong>the</strong><br />

same services in one WinForm app for <strong>the</strong> purposes of demoing <strong>the</strong> code base. If both are on <strong>the</strong>y will steal messages<br />

from each o<strong>the</strong>r.<br />

6.1.1 To Run<br />

Open up ~/Samples/Starbucks/Starbucks.sln<br />

Start <strong>the</strong> following projects<br />

/Starbucks.Barista<br />

/Starbucks.Cashier<br />

/Starbucks.Customer<br />

Enjoy.<br />

6.2 Heavy Load<br />

This sample attempts to push <strong>the</strong> limits of <strong>the</strong> infrastructure, and can be run as a gauge on your hardware?s capacity<br />

to perform.<br />

6.3 Open All Night<br />

This sample attempts to be a long term test of <strong>the</strong> infrastructure, and can be set to run for a set number of time. It<br />

works with <strong>the</strong> prebuilt services as well, to both quickly test and to put through <strong>the</strong>ir paces over time.<br />

6.3.1 Overview<br />

This sample is used to both test <strong>the</strong> pre-built services and perform long running (multi-hour) stress tests.<br />

59


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

6.3.2 To Run<br />

Open up $/Samples/OpenAllNight/OpenAllNight.sln<br />

Start <strong>the</strong> following projects (in order)<br />

/<strong>MassTransit</strong>/RuntimeServices<br />

/OpenAllNight<br />

Starbucks - This sample attempts to be a complete sample of a message based solution as well as a concrete example<br />

of Gregor Hophe’s article “Starbucks doesn’t use two phase commit.<br />

HeavyLoad - This sample attempts to push <strong>the</strong> limits of <strong>the</strong> infrastructure, and can be run as a gauge on your hardware’s<br />

capacity to perform.<br />

OpenAllNight - This sample attempts to be a long term test of <strong>the</strong> infrastructure, and can be set to run for a set number<br />

of time. It works with <strong>the</strong> prebuilt services as well, to both quickly test and to put through <strong>the</strong>ir paces over time.<br />

60 Chapter 6. Samples


CHAPTER 7<br />

<strong>MassTransit</strong> Learning Series<br />

For many developers, asynchronous messaging is a new pattern. In this series of learning exercises, developers will<br />

learn how to create applications using asynchronous messaging with <strong>MassTransit</strong>.<br />

This series covers using <strong>MassTransit</strong> with RabbitMQ. The skills, however, are relevant regardless of which messaging<br />

transport is used. There are some operational differences between <strong>the</strong> transports, but <strong>the</strong> programming interface<br />

remains <strong>the</strong> same.<br />

It is recommended that <strong>the</strong> learning exercises be completed in order, as more advanced exercises build upon skills that<br />

were learned in <strong>the</strong> earlier exercises.<br />

7.1 Requirements<br />

To perform <strong>the</strong> learning exercises, <strong>the</strong> following applications should be installed.<br />

Visual Studio 2010 Service Pack 1 NuGet Package Manager (see Installing NuGet)<br />

NuGet requires an internet connection to download packages.<br />

7.2 Creating Your First Consumer<br />

To create your first consumer, create a new project using Visual Studio. The project should be configured to use .NET<br />

4.0, and should be created as a class library. In this exercise, <strong>the</strong> project name is “LearningMT.OrderConsumer”.<br />

61


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

Once <strong>the</strong> project is created, delete <strong>the</strong> Class1.cs file which was automatically created.<br />

A reference to <strong>MassTransit</strong> must now be added, which you will do using <strong>the</strong> NuGet package manager. To add <strong>the</strong><br />

reference, right-click on <strong>the</strong> project References and select Manage NuGet Packages from <strong>the</strong> context menu.<br />

Select <strong>the</strong> Online section on <strong>the</strong> left, and enter <strong>MassTransit</strong> into <strong>the</strong> search box. Once <strong>the</strong> results are displayed, select<br />

<strong>the</strong> <strong>MassTransit</strong>.RabbitMQ package and click Install. This will install <strong>the</strong> RabbitMQ transport, and its dependencies,<br />

62 Chapter 7. <strong>MassTransit</strong> Learning Series


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

which include <strong>MassTransit</strong> itself. You many have to click <strong>the</strong> license acceptance box to continue.<br />

Once <strong>the</strong> package manager is finished downloading <strong>the</strong> package and adding <strong>the</strong> references, close <strong>the</strong> package manager<br />

and verify that <strong>the</strong> references have been added to your project. Note that some unneeded references added by Visual<br />

Studio have been removed.<br />

7.2. Creating Your First Consumer 63


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

7.2.1 Adding <strong>the</strong> Message Contract<br />

Using <strong>MassTransit</strong>, <strong>the</strong>re are several ways that message subscriptions can be added to a service bus instance. In this<br />

exercise, you will be creating a message consumer. O<strong>the</strong>r types of message subscriptions include message handlers,<br />

consumer instances, and sagas.<br />

Before creating your consumer, however, you must first define a message. Using <strong>MassTransit</strong>, messages should be<br />

defined using C# interfaces. To create a message, add a new interface to <strong>the</strong> project called SubmitOrder.<br />

1 using System;<br />

2 using <strong>MassTransit</strong>;<br />

3<br />

4 public interface SubmitOrder :<br />

5 CorrelatedBy<br />

6 {<br />

7 DateTime SubmitDate { get; }<br />

8 string CustomerNumber { get; }<br />

9 string OrderNumber { get; }<br />

64 Chapter 7. <strong>MassTransit</strong> Learning Series


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

10 }<br />

The interface defines <strong>the</strong> message contract that <strong>the</strong> consumer accepts. In this exercise, you are creating a service that<br />

accepts <strong>the</strong> SubmitOrder command. Command message contracts are defined and owned by <strong>the</strong> service and specify<br />

<strong>the</strong> input requirements for <strong>the</strong> service.<br />

The properties on <strong>the</strong> interface are defined with getters only, because message contents are immutable. The interface<br />

extends <strong>the</strong> CorrelatedBy interface, specifying that a Guid should be used for message correlation. Correlation allows<br />

<strong>the</strong> message to be tracked from <strong>the</strong> message produder to <strong>the</strong> message consumer.<br />

7.2.2 Adding <strong>the</strong> Consumer Class<br />

A consumer in <strong>MassTransit</strong> is a class that implements one or more Consumes interfaces. To create <strong>the</strong> consumer, add<br />

a new class to <strong>the</strong> project called SubmitOrderConsumer as shown.<br />

1 using <strong>MassTransit</strong>;<br />

2<br />

3 public class SubmitOrderConsumer :<br />

4 Consumes.Context<br />

5 {<br />

6 public void Consume(IConsumeContext context)<br />

7 {<br />

8 }<br />

9 }<br />

The Consume method is defined by <strong>the</strong> Consumes.Context interface, and is used by <strong>MassTransit</strong> to<br />

identify <strong>the</strong> message type for <strong>the</strong> consumer. At this point, <strong>the</strong> consumer has no behavior, but has enough code to<br />

continue <strong>the</strong> exercise.<br />

7.2.3 Creating a Service Bus Instance<br />

With <strong>the</strong> consumer class created above, you are now ready to subscribe that consumer to an instance of a <strong>MassTransit</strong><br />

service bus. However, you must first create a service to host <strong>the</strong> service bus.<br />

Create a new class in <strong>the</strong> same project called OrderService as shown below.<br />

1 using <strong>MassTransit</strong>;<br />

2<br />

3 public class OrderService<br />

4 {<br />

5 IServiceBus _bus;<br />

6<br />

7 public void Start()<br />

8 {<br />

9 _bus = ServiceBusFactory.New(x =><br />

10 {<br />

11 x.UseRabbitMq();<br />

12 x.ReceiveFrom("rabbitmq://localhost/learningmt_orderservice");<br />

13 });<br />

14 }<br />

15<br />

16 public void Stop()<br />

17 {<br />

18 _bus.Dispose();<br />

19 }<br />

20 }<br />

7.2. Creating Your First Consumer 65


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

In <strong>the</strong> class above, two methods have been added, Start and Stop. In <strong>the</strong> Start method, <strong>the</strong> ServiceBusFactory is used<br />

to configure an instance of <strong>the</strong> service bus, which includes specifying <strong>the</strong> input queue for <strong>the</strong> bus instance. The Stop<br />

method disposes of <strong>the</strong> bus instance, which is necessary to ensure that all pending subscriber threads have completed.<br />

7.2.4 Testing <strong>the</strong> Service Bus Instance<br />

At this point, <strong>the</strong>re is a lot of code written and no unit tests. To fix that, create ano<strong>the</strong>r project in <strong>the</strong> solution called<br />

LearningMT.OrderConsumerTests. Once created, use <strong>the</strong> NuGet Package Manager to add NUnit to <strong>the</strong> project. (If<br />

you are running Visual Studio 2012/13, you may want to NuGet “NUnit TestAdapter including NUnit...framework”<br />

instead.) Then add a reference to your LearningMT.OrderConsumer project. Finally, NuGet “<strong>MassTransit</strong>.RabbitMQ”<br />

(which includes <strong>MassTransit</strong>) like you did for <strong>the</strong> original OrderConsumer project.<br />

After creating <strong>the</strong> tests project, create a new unit test (e.g., copy <strong>the</strong> following in to a new class), build <strong>the</strong> project,<br />

and <strong>the</strong>n click/run “Should_create_<strong>the</strong>_service_bus” in <strong>the</strong> Test Explorer window to verify <strong>the</strong> OrderService can be<br />

started and stopped. (This will ensure that your project and dependencies are all setup correctly and that RabbitMQ is<br />

installed and configured properly as well.) Basic unit test code is shown below.<br />

1 using NUnit.Framework;<br />

2 using OrderConsumer;<br />

3<br />

4 [TestFixture]<br />

66 Chapter 7. <strong>MassTransit</strong> Learning Series


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

5 public class Starting_an_order_service<br />

6 {<br />

7 OrderService _orderService;<br />

8<br />

9 [TestFixtureSetUp]<br />

10 public void Before()<br />

11 {<br />

12 var orderService = new OrderService();<br />

13 orderService.Start();<br />

14<br />

15 _orderService = orderService;<br />

16 }<br />

17<br />

18 [TestFixtureTearDown]<br />

19 public void Finally()<br />

20 {<br />

21 if(_orderService != null)<br />

22 {<br />

23 _orderService.Stop();<br />

24 _orderService = null;<br />

25 }<br />

26 }<br />

27<br />

28 [Test]<br />

29 public void Should_create_<strong>the</strong>_service_bus()<br />

30 {<br />

31 }<br />

32 }<br />

The test fixture setup and teardown code manage <strong>the</strong> creation, starting, and stopping of <strong>the</strong> service. The unit test itself<br />

is empty since this test is only verifying that <strong>the</strong> bus can be created.<br />

7.2. Creating Your First Consumer 67


<strong>MassTransit</strong> <strong>Documentation</strong>, Release 2.0<br />

68 Chapter 7. <strong>MassTransit</strong> Learning Series


CHAPTER 8<br />

Indices and tables<br />

• genindex<br />

• modindex<br />

• search<br />

69

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!