In the last week of November, Dave de Florinier and I did a talk on Asynchronous .NET architectures and NServiceBus. The sound of the recording was not that good so some readers asked for a transcript. The following is a transcript of my introduction to the talk, encouraging developers to investigate messaging architectures for mid-size and smaller projects. I’ll try to get the rest of the talk published here soon as well.
Today, we use web and web-related services for content distribution, for remoting, for application partitioning and distribution. It seems that HTTP calls have become a default way to think about distributed systems. HTTP and Web services definitely have a lot to offer, but they are not the only way to do things and there are definitely cases where web is not the right choice. HTTP calls are synchronous, stateless (although there is a state simulation with cookie-based sessions) and generally not that reliable. They are also often one-way, which means that any kind of continuous notification always comes down to polling. When you need asynchronous actions, proper state and reliability or event driven behaviour, Web is not the right choice. Unfortunately, lots of people just stick with web services and hack on, trying to fit a square peg in a round hole. In cases such as these, a different distribution paradigm can save us quite a lot of time and effort both in development and later in maintenance. One of those different paradigms is messaging.
I’m not sure why, but I got the impression that lots of people think that messaging is only for huge systems in investment banks, not something that a small or a mid-size project should consider at all. This is false and now I’ll try to convince you.
In a nutshell, messaging allows us to reliably break up a single process into several parts which can then be executed asynchronously. They can be executed with different threads, or even on different machines. The parts communicate by sending each other messages. The messaging framework guarantees that messages get delivered to the right recipient and wake up the appropriate thread when a message arrives.
Fire and Forget
Messaging is a great solution when you want to ensure that something gets done, but you don’t really care about the results and you don’t want to wait for it to finish. This kind of behaviour can often be found when the last part of a process requires talking to an external system or some sort of batch processing.
For example, after a user registers on the web site we want to send him a confirmation e-mail, but there is not much point in waiting for the e-mail to be sent to continue the work. We can send the e-mail synchronously from the web page, but that means blocking up the web server request (and a thread on the server and the user looking at the page and any other resources that the page holds such as a database connection) while the e-mail is sent through an external server. Another solution is to split this process into two parts. The actual registration is really important to finish while the user is there so that he can correct any problems, so that gets done synchronously. Instead of actually sending the e-mail, the web page can just enqueue an e-mail request in a form of a message and then finish working. This releases the database connections, threads and other server resources and returns the page to the user faster. The messaging framework then delivers this request to a dedicated e-mail sender which can dispatch the e-mail in the background. In addition to making the system more responsive, this approach also makes it more resilient. If the e-mail server is temporarily down or there is a DNS problem, the primary process will not be affected and the background process can retry after a while. If the background process is processor or resource intensive, this approach enables us to scale it better because we can have several workers waiting to handle requests from the primary part of the process. If the secondary part of the process is time-consuming, this approach enables the user to go offline knowing that the work will actually be done, and done only once. Remember messaging every time you create a page that contains something like “do not close this window, click on back or reload the page until you see a confirmation”. Messaging also makes the whole thing easier to test because we can check the contents of the message request from a unit test, without actually sending the e-mail. I wrote about this in a bit more detail earlier in How to test e-mail notifications properly.
In any case, fire and forget is incredibly easy to implement with messaging and really hard to (properly) do it with a synchronous stateless unreliable platform such as web.
Just leave it there when you’re done
Another very interesting case is when there is a resource intensive or a time consuming operation that we want to execute and we care about the results, such as generating a long report or processing transactions with external payment providers. Messaging can also help a lot with this case. Instead of a single web request that consumes resources during the whole process, we can split it into the initial part that has to be done synchronously (collecting the report criteria or storing transaction information), assign an ID to that task and then break into two branches. The actual work gets done in the background, decoupled with messaging. For example, a background process picks up the report request and assembles it, saving a PDF to a predefined location on the disk. The second branch is executed by the browser, periodically checking with the server whether the work is done by passing the request ID. When the request is finally done, the client can ask for the results. The web server resources are released straight after the initial part, so that other users can utilise the server and we get better responsiveness and better resource usage. Again, this approach enables us to scale the system better – we can have many workers on many different machines building reports or processing transactions to help the system to scale, or we can limit the number of workers and ensure that scarse resources such as database connections or payment gateway links are available to a much larger number of web servers. I wrote about this earlier in Lazy Web Sites Run Faster.
Share the load
This brings me to the third really useful situation when messaging should be considered. Whenever lots of different agents can request some work to be done, consider messaging as a way to decouple requesters and workers. Web services allow us to scale processing using simple HTTP load balancing, but this gets quite tedious to set up when the number of participants in the process grows. The requester must know how to call the worker and who the worker is. A messaging solution might help to divide and conquer, isolating parts of the system so that they don’t really care about each other. It also makes the system easier to scale and extend. The agents can just publish requests to a message queue, not caring about who and where will actually process them. A number of different processes, running on different machines, can pick up requests and service them, pushing the results back to the message queue. The results might be delivered back to the original requester or picked up by another worker to continue or complete the job.
Thinking about processing in this way allows us to scale the system at runtime much easier (just start up more workers that listen on the queue), extend the system easier (have specialised workers to process particular types of messages) or make the system more flexible (start up workers overnight to pick up low-priority tasks). All these changes can be done in runtime, without touching the code at all.
The key to efficient asynchronous architectures
I hope that, by this point, I’ve at least tickled your imagination and possibly convinced you that messaging can help you do your job easier in some cases. The key to actually getting this done is having an efficient messaging framework in between, that coordinates processing and guarantees that messages actually get delivered. This framework is there to do the heavy lifting and our code should just be concerned with sending or picking up the messages and acting on them.
Maybe people are afraid of messaging because it is typically mentioned in the context of expensive application servers or service bus products, but there are some really lightweight and free (opensource) solutions for messaging as well. So you don’t have to pay a lot of money or hire expensive consultants to benefit from messaging. One such framework for .NET is NServiceBus, which utilises Microsoft’s MSMQ queues, makes MSMQ programming dead easy and implements several really useful communication patterns for you out of the box. For Java, there is the Apache ActiveMQ, which is really straightforward to set up and even supports Ajax and Flash clients almost out of the box. Apache Camel implements various enterprise integration patterns out of the box with ActiveMQ.
I'm Gojko Adzic, author of Impact Mapping and Specification by Example. My latest book is Fifty Quick Ideas to Improve Your Tests. To learn about discounts on my books, conferences and workshops, sign up for Impact or follow me on Twitter. Join me at these conferences and workshops:
Specification by Example Workshops
How to get more value out of user stories
- Vienna, AT, 4 March 2016