Chris Patterson is active in the open-source community and has created many projects, including MassTransit, a distributed application framework for .NET. He is a Principal Architect at McKesson, the oldest and largest healthcare company in the nation. Chris is responsible for architecture supporting applications and services that enable McKesson’s distribution and technology solutions around the globe. He also is a regular conference speaker, sharing his knowledge and experience with developers across the world. Chris is a 13-year Microsoft MVP Award winner for his contributions to the software development community.
Chris, welcome back to the show. Now some of the listeners might have heard your previous interview or seen you speak. Tons of people use your new projects one of which being MassTransit which we are discussing today. But for those of you who haven’t become familiar with you, can you give us a little background on what are the high points in your career that led up to what you’re focusing on today?
Let me say I’ve been a lifetime software developer. I think the first application I wrote was a game on an Apple IIe. So that gives you some perspective of how long I’ve been doing this. But when I first started out in my major professional career, I was building a lot of distributed systems. And back then it was NetBIOS and IPX. Novell networks were the rage. My start in network communication and distributed applications was early on and it’s continued throughout my career.
I’d say some of the biggest points were jumping into the SOA 1.0 world and then recognizing the challenges of that. It was 14 or 15 years ago, getting together with the first ALT.NET meeting down in Austin meeting a lot of people and getting a completely different perspective than the canonical out of the book perspective. This is how you build software using Microsoft tools and technologies. It was an eye-opening thing, and I met a lot of cool people.
You look at the Microsoft of today where things like Microsoft extensions, dependency injection, and configuration and options, and all of these things are just de facto out of the box standards now. Now it is a super compelling, super-fast, super powerful platform. If you look at the tech and power benchmarks, we are in the top six which is good company to be in.
I’ve been asked many times how to describe MassTransit. If I’m talking to a developer who understands different languages and different tool sets, I can say it’s like the JMS of .NET because that is one thing .NET has never had is an abstraction over messaging. Java has had JMS Java message service, which provides kind of a loosely lowest common denominator API of messaging for Java applications regardless of transport.
MassTransit is an abstraction. It sits on top of message transport such as RabbitMQ or Azure Service Bus or even Amazon SQS, and even in some cases ActiveMQ. If you are coming from a .NET background, it is like ASP.NET for messaging. You create consumers, which are very much in line with what a controller would be. The consumers can handle different message types, which translate to action methods, and you are able to have that same kind of programming experience where you create consumers.
You register them on the bus configuration, and mass transit handles all the work of setting up the subscriptions, creating the queues, creating topics, routing messages, and delivering them to your consumers. Much like ASP.NET when a message arrives in a queue, you are not reading it. You don’t have to deal with any transport work.
MassTransit’s a Hollywood principal framework and we’ll call you so when a message arrives on the queue, mass transit gets that message, converts it to a .NET type, so you only must deal with types just like you do with a model in a controller action. It creates an instance of your consumer from the container letting you have all the dependencies you need, calls a method on your consumer to let you consume that message. From that method, you can produce other messages or you can talk to databases, you can respond, etc.
Once you are done, MassTransit acknowledges the messages on the transport which moves it out of the queue and handles that whole lifecycle for you. It really makes it easy to build “activate me” applications. We are like ASP.NET but against any message transport, and the wonderful thing about mass transit is you can write at once.
MassTransit also has an in-memory transport. You can test unit tests and for all the unit tests you write it has a lot of extensive test harness support. Sometimes people will test locally with RabbitMQ, and then when they deploy to Azure Kubernetes or just App Service, they will run their application on Azure Service Bus. They do not have to rewrite any of the code. It is just two different settings. Whether you are configuring the bus for RabbitMQ or Azure Service Bus, MassTransit handles all the translations between RabittMQ exchanges versus Azure Service Bus topics. Whereas if you are going to Amazon, it’s SNS topics that then send messages to SQS. It has really made it easy to disconnect yourself from the transport, the implementation, and focus purely on writing the logic.
Why would you choose in production Rabbit versus the traditional Azure queues versus the Azure Service Bus topics? What’s the thought process there?
It’s an interesting question. The most widely used transport with MassTransit is RabbitMQ and for good reason, it’s a solid Message Broker. You can run it in a container, and you can run it through CloudAMQP. Amazon has hosted RabbitMQ now, so there really are a lot of opportunities to take advantage of RabbitMQ and I think cloudAMQP even hosts in Azure and GCP.
Now, through the marketplace, you can just run it in your subscription and install it through the marketplace and be billed through your Azure credits. Azure Service Bus is a full featured Message Broker. It has a lot of the capabilities that you would expect. It has decent throughput, I think in the data center with a fairly large premium plan I was getting like 6000 messages a second, which is pretty decent. RabbitMQ by comparison on my local machine, I get like 18,000 a second.
If you’re going cloud native and if you’re all in on Azure, is there a compelling reason to grab RabbitMQ versus “you know what Azure just do it for me” as your service bus?
It’s just whatever messaging patterns you need. If you’re just doing messaging, publishing and just some loose coupling within your applications, either work. There’s a lot of reliability and transient issues with Azure Service Bus. You can get throttled quickly depending on your pricing plan because they do a lot of rate limits. It really just depends on cost and message volume and what your expertise of your operations staff are. There’s no compelling reason to choose one or the other. It’s just whatever you’re comfortable with.
Is MassTransit just for the asynchronous or is it for any way that a program could talk to another program?
MassTransit, besides just being an abstraction on top of message queues, has a large assortment of middleware components that you can use for things like retry redelivery, fault handling, circuit breakers and kill switches.
MassTransit can do both. It can do the asynchronous, but it can also be the request response type patterns because you can do those over messaging. There isn’t any reason not to.
It can send a message and wait for the response, and it does all the coordination for you. You get a very HTTP client like experience with the request client that’s part of MassTransit. You can just send a message and say, “Okay, well, I’m going to wait 30 seconds for a response timeout.” But you must recognize that that message may have been received and processed. You just didn’t wait long enough for the response. It just gives you flexibility in how you want to handle it.
Have you seen a way to consolidate the serialization of the Data Transformation Object (DTO) types so you don’t have to have specific types all over the place just because you have to be on a different channel?
When you talk about DTOs and message type, what you’re really alluding to is there’s a contract between a client and a server. MassTransit is very code first, and it’s very developer focused.
There are definitely types involved, and they’re usually clear. The trick is how do you document those? And that’s always been the hard question. What do those look like? Where do we inventory those? Where do we have like our API documentation for message-based services?
And if we ever get a good answer for that, I’ll let you know. Because we still don’t have it. There’s no good answer. There have been a lot of attempts to try to solve that problem. It is a hard problem to create, like an enterprise service directory catalog.
Now, as a as a service owner, thinking about the architecture of it, isn’t it fair to ask whether you want your server endpoints to be directly called by your customers, or whether you want to provide them with an API that then let some of your code run in their process? What are your thoughts about that?
We talked about that a couple days ago. Someone asked, “How do I set up security so that I can have all of my remote devices connect directly to Azure Service Bus and submit messages?” and I thought in my head, “Why would you do that? Why would you not just have API endpoints that are running up in a nice global directory load balancer in Azure and have your mobile devices talk to that API and leave messaging for the internal network?”
I recognize that some people think it would be cool and believe it or not, MassTransit runs on iOS. If you compile it down using whatever that tool is. I think that’s the Xamarin stuff. The compiler compiles down to a native iOS app, and you can run MassTransit on an iPad application that’s connecting back up to RabbitMQ or Azure. I was surprised that worked. We had to make some type changes to get it to fully work.
Then the question is what happens when the network isn’t available? When a UPS truck goes under a bridge, and it’s trying to update its location from the iPad application, how does that connect?
No, it’s totally true, even simple security is one thing but even as simple as throttling. In some instances, if I can write some code that you are going to run in your process on your device, then it gives me a surface area to put some logic where I can say, “You know what, I returned that exact answer from my side really quickly.” They have some default caching right there on the client, or whatever logic may seem appropriate.
If you own the end user device, and it’s always going to be say, iOS or Android or Windows platform or even if it is just running on atom or electron, you can control the experience and provide a better, consistent programming model versus just saying these are our API endpoints. There are certainly cases where that makes sense. Again, it’s just the maintenance of it.
If I was providing a React plugin to call our API that gives a better experience than just trying to figure out our API’s natively, I would totally publish that NPM and use it in different cases because I think it would make sense. Right now, the hardest thing about communicating with developers is to get them in the same mindset and to get them to figure out how your API should be called the way you’ve thought about it being called versus the way they see it. Because a lot of times it is different people just come from a different background and a different experience. When they approach an API, they don’t think about it the way you thought about it when you wrote it.
Just following some of the consistent paradigms of the language that you’re in. If you are creating a Vue JS component or React component, and you are making it work with the idiomatic behaviors of other components within that UI framework, but behind the scenes, you’re doing your connection to AMQP and writing directly to RabbitMQ. Rock on if you can make it easier for a developer to adapt their solution to use your service. Now that’s a win for everybody!
It seems like the use of the term API application programming interface has been in the minds of a lot of people to use as a synonym for HTTP web service. An API is a way to call some type of function entry point or program, not just web service through TCP hosted through a web server. But are we ever going to recover that API? Do we need another term or do we need to reinforce how many types of API’s there can be?
It’s an API. It’s a Interface Standard. It’s all just a bag of properties that you throw around, the process memory, the network, so that some method knows the incoming arguments and how to behave.
When MassTransit Errors
Well, as we close, let’s tackle a problem that everybody has with messaging. When something is wrong with a processor, and messages are just going to dead letter, let’s talk about that process. What do you do? How do you prevent it? How do you recover?
So you mean systems don’t always work perfectly?!
When a consumer throws an exception in MassTransit, after the retries are exhausted and the redelivery attempts or rate limit is reached, MassTransit is going to move it to an error queue. In Azure, you can configure it to use the built-in dead letter queue of Azure. Managing those is tricky. Your operations team needs to manage that. They need to either be tracing the logs or monitoring events produced by MassTransit.
There is middleware that can try to catch those and limit the bleeding so to speak. That’s ultimately what it comes down to if your system does just go belly up. Typically, your team is then stuck with, “How do I move those back into the processing queue once things are ready?” The management tools for that are not great. I will say that they may be getting better. There may be some certain projects underway to create SAS based services to connect to your brokers and do some operational management tooling around the different queues.
There may be more to come on that by the end of the year. I do know people that are well underway and building some of these operational tool sets to run on time and not just for MassTransit, but any message-based transport. Putting in place a nice SAS platform to monitor and run your applications is important. The benefit of that is that you have the asynchronous process. You have the message and you’ve acknowledged their request. They’ll be able to process it again once you get your systems recovered.
With web services, if something bad happens, your user is expected to take a compensating action. If there’s no way that the user can take a custody action, besides call tech support, it makes it difficult. on the corollary if if we take a customer’s order, and we just take it, we do form validation on the wrong side of the wire when our operational teams like I don’t have an address for this order. And so it’s really, who can actually fix certain type of errors. Those are important decisions.
More Information Please
Well, Chris, we’ve come to the end of our visit. Is there any particular URL or resource that you want listeners to look into if they have an interest in this right away?
The first place to go is just search for MassTransit project. Visit the MassTransit webpage to find the documents. From there you’ll find everything from getting started such as the repos and sample apps. There’s a Discord channel that I seem to be on way more than I should be! MassTransit is free. There’s no charge to use it, and there never will be.