How to use Rebus in a web application

If you’re building web applications, you will often encounter situations where delegating work to some asynchronous background process can be beneficial. Let’s take a very simple example: Sending emails!

We’re in the cloud

Let’s say we’re hosting the website in Azure, as an Azure Web Site, and we need to send an email at the end of some web request. The most obvious way of doing that could be to new up an SmtpClient with our SendGrid credentials, and then just construct a MailMessage and send it.

While this solution is simple, it’s not good, because it makes it impossible for us to have higher uptime than SendGrid (or whichever email provider you have picked). In fact, every time we add some kind of synchronous call to the outside from our system, we impose their potential availability problems on ourselves.

We can do better 🙂

Let’s make it asynchronous

Now, instead of sending the email directly, let’s use Rebus in our website and delegate the integration to external systems, SendGrid included, to a message handler in the background.

This way, at the end of the web request, we just do this:

and then our work handling the web request is over. Now we just need to have something handle the SendEmail message.

Where to host the backend?

We could configure Rebus to use either Azure Service Bus or Azure Storage Queues to transport messages. If we do that, we can host the backend anywhere, including as a process running on a 386 with a 3G modem in the attic of an abandoned building somewhere, but I’ve got a way that’s even cooler: Just host it in the web site!

This way, we can have the backend be subject to the same auto-scaling and whatnot we might have configured for the web site, and if we’re a low traffic site, we can even get away with hosting it on the Free tier.

Moreover, our backend can be Git-deployed together with the website, which makes for a super-smooth experience.

How to do it?

It’s a good idea to consider the backend a separate application, even though we chose to deploy it as though it was one. This is just a simple example on how processes and applications are really orthogonal concepts – in general, it’s limiting to attempt to enforce a 1-to-1 between processes and applications(*).

What we should do is to have a 1-to-1 relationship between IoC container instances and applications, because that’s what IoC containers are for: To function as a container of one, logical application. In this case that means that we’ll spin up one Windsor container (or whichever IoC container is your favorite) for the web application, and one for the backend. In an OWIN Startup configuration class, it might look like this:

In the code sample above, UseWindsorContainer and RegisterForDisposal are extension methods on IAppBuilder. UseWindsorContainer replaces Web API’s IHttpControllerActivator with a WindsorCompositionRoot like the one Mark Seemann wrote, and RegisterForDisposal looks like this:

which is how you make something be properly disposed when an OWIN-based application shuts down. Moreover, I’m using Windsor’s installer mechanism to register stuff in the containers.

Rebus configuration

Next thing to do, is to make sure that I configure Rebus correctly – since I have two separate applications, I will also treat them as such when I set up Rebus. This means that my web tier will have a one-way client, because it needs only to be able to bus.Send, whereas the backend will have a more full configuration.

The one-way client might be configured like this:

this registering an IBus instance in the container which is capable of sending SendEmail messages, which will be routed to the queue named backend.

And then, the backend might be configured like this:

Only thing left is to write the SendEmailHandler:

Email message handler

Conclusion

Hosting a Rebus endpoint inside an Azure Web Site can be compelling for several reasons, where smooth deployment of cohesive units of web+backend can be made trivial.

I’ve done this several times myself, in web sites with multiple processes, including sagas and timeouts stored in SQL Azure, and basically everything Rebus can do – and so far, it has worked flawlessly.

Depending on your requirements, you might need to flick on the “Always On” setting in the portal

Skærmbillede 2015-08-21 kl. 11.44.22

so that the site keeps running even though it’s not serving web requests.

Final words

If anyone has experiences doing something similar to this in Azure or with another cloud service provider, I’d be happy to hear about it 🙂


(*) This 1-to-1-ness is, in my opinion, a thing that the microservices community does nok mention enough. I like to think about processes and applications much the same way as Udi Dahan describes it.

8 thoughts on “How to use Rebus in a web application

    1. Rebus can be used pretty much anywhere, but it requires some kind of “transport” to work. E.g. in Azure, you would configure Rebus to use either Azure Storage Queues or Azure Service Bus, or if you’re running on-premise, you could configure Rebus to use MSMQ (if you’re running on Windows servers) or RabbitMQ (if you’ve installed a RabbitMQ server), or even SQL Server can be used as a transport.

  1. I am looking for code sample for Azure Service Bus, like Topic and queue? Please provide links.

  2. Hi Guys;
    I am interested in Rebus.
    Actually I have explored MassTransit, Rhino Service Bus,NServiceBus (very expensive) etc and lastly the Rebus.
    I have been actually impressed by its capability and simplicity especially transactional message sending.
    Can you kindly share an example on how to configure Rebus in a Web Application.
    I need something to get started with where I will extend.
    I tried to follow a tutorial on using Rebus with AzureServiceBus but I was get an Error with AutofacContainerAdapter not defined.
    I think the examples included in the Samples are very minimal.
    Regards

    1. Hi Amour, sorry for replying so late to this comment – apparently, my website does not notify me in any
      way, when someone comments on posts. 😐

      In case anyone Googles it, I’ll just repeat my reply here:

      Really happy to hear that you like Rebus! 😎

      On how to host Rebus in a web application, I think this blog post explains it pretty well. If there’s something you think is not clear, please let me know.

      Regarding the error with Autofac: My guess is that updating to the latest prerelease of Rebus.Autofac (6.0.0-b07 at the time of writing) will solve your problem.

  3. Hi Mogens.

    Thanks for an interesting article. But I don’t understand the need for a service bus in this situation. As far as I can see that is just adding unnecessary complexity. If you are in Azure then you can just use a regular Azure queue. The handler of the queue would be as simple as your SendEmailHandler and you would avoid the additional dependency.

    For the “Send email” scenario what benefits does Rebus give you compare to just a regular Azure queue?

    Thanks,
    Anders

    1. Sure, you can use a regular Azure Storage Queue, and Rebus can help you do that via the Rebus.AzureQueues NuGet package.

      But to be able to handle messages from that queue, you need to receive them somewhere… so you’d need some kind of thread that polls for messages… but maybe it should back off a bit during periods of low activity, so you’re not billed for too many poll requests…. and then you receive a message, so you probably need to serialize/deserialize the message contents… and if you want dependency injection, you need a mechanism to somehow construct handlers… and what if there’s an exception? Then you probably need some logging, a retry mechanism, and also a dead-letter queueing mechanism, so poison messages don’t end up clogging the pipes… etc. etc. 🤠

      All that comes for free with Rebus. And with the added bonus that you can switch to Azure Service Bus by going .Transport(t => t.UseAzureServiceBus(...)) instead of .Transport(t => t.UseAzureStorageQueues(...)), or RabbitMQ by going .Transport(t => t.UseRabbitMq(...)), or to an in-mem transport for your build server by going .Transport(t => t.UseInMemoryTransport(...)) etc.

      Some people might still be happy with coding their own messaging frameworks though, and – being guilty of having done so myself 🤓 – I actually encourage people to have a go at it! For very simple scenarios, you might not need all of the things I just mentioned, and then you might be better off with a simple homemade message receiver… but I’ve also often seen people underestimate the intricacies of being able to do proper message handling, so I mostly just hope that people will try to think their requirements through and make informed decisions.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.