Why not publish NServiceBus messages from a web application?

It may be the single most asked question on the NServiceBus Yahoo Group, and it usually goes something like this:

The NServiceBus Documentation/FAQ says not to publish messages from a web application. But…why?

All the documentation says on the topic amounts to “Don’t. Bus.Send() a message instead.” This is true and good practice, but developers are smart people that aren’t commonly happy with an answer that doesn’t include a why.

In this article I’ll go into some depth on the three main reasons why you’re better off using Bus.Send() when in the web world than Bus.Publish().

Transactions and Consistency

Messages that are published on the bus are like events – they should announce something that has already happened. If the thing didn’t happen, no event should be published, and if for some reason the event cannot be published, the work that is being announced should be rolled back as well.

With an NServiceBus transactional endpoint, we get this for free – each message is handled within a TransactionScope and succeeds or fails as an atomic unit.

In a website, we aren’t so protected by default. In a web environment, we respond to an HTTP request, not a queued, replayable message. If we alter state in some way, and then the web service fails, we will never get the opportunity to announce that work to the world, and our application may be left in an inconsistent state.

But, you say, I’ll wrap the work and the Bus.Publish() in a TransactionScope and then everything will be atomic. This is better – you can no longer leave the application as a whole in an inconsistent state. However, the original HTTP request is lost. The user gets an error message and will have to repeat their request. However it negates some of the benefits inherent in NServiceBus.

Some people may think that the NServiceBus documentation, by saying to Send() and not Publish(), is telling them to send a message an application layer to essentially publish the same information without doing any work, but this is incorrect. What the documentation really means is that when the web request is received that requires a change of application state, you should immediately send a command to the application layer, and then have the application layer do all the work and publish the result message. This method turns the loss-prone HTTP request into a durable message that can be queued and retried.

The added benefit of this methodology is that it turns your web application into a semi-dumb face that displays cacheable data and accepts user inputs, which means your website scalability can go through the roof, being liberated of all the heavy lifting that was previously weighing down the web application’s thread pool.

This development pattern is difficult for some development teams to grasp. Let’s face it, when many of us start with NServiceBus, we are one developer on a team who thinks this messaging stuff is pretty cool. The rest of the developers on the team may not be totally on board yet. They may balk at having to simultaneously run a bunch of console windows in order to have the website do anything. Maybe there’s the cranky old-timer on the team who got burned by MSMQ one time years ago and now swears that anything that uses it is garbage.

In any case, NServiceBus can have a bit of a learning curve and instead of immediate immersion, it can be easier to wade in as you begin to feel comfortable. In these situations a developer may only want to use NServiceBus for certain long-running processes that can’t complete within a normal web request time window. In my opinion, this is totally fine. In these situations you could conceivably publish events from within a web application as long as a TransactionScope ensure atomicity. NServiceBus will not stop you from doing so, however I still recommend against it. If you constrain your event publishing to a back-end application service, it will help in the future when you want to more fully embrace using NServiceBus to its full potential, as you won’t have to change subscription configurations when you move functionality into the application layer.

Web Application Scale-Out

So you’ve decided you can live with all that, and you still want to publish events from your web application. You code up a couple services that subscribe to MyNeatEvent messages coming from MyWebsite@MyWebserver. Awesome. You get your code in production, and you become a victim of your own success – the web server is having trouble handling the load and you need to load balance just to keep up with the traffic, much less deal with maintenance and updates.

Uh-oh.

The new load-balanced web server will have its own local input queue, MyWebsite@MySecondWebserver. You’re now publishing messages from two locations, which would mean subscribers would need to subscribe to the message from two locations. I’m not even sure NServiceBus will allow this; I haven’t tried it and don’t want to, because even if it worked, it would be a mess.

If you had published that event from an application service, you could easily scale out your website. The new website node would just be another location sending commands to the application layer.

If the application service needs to be scaled out, you can put a Distributor in front of the service’s input queue and then have worker nodes on as many servers as necessary request work from the distributor. Both layers can be scaled out simply painlessly.

Web App Recycling

I consider this the lesser of the three reasons, but it still bears mention. IIS automatically recycles worker processes. This means that at any moment, your NServiceBus-endpoint-in-a-webapp could cease to be, replaced by a new one, or in the case of a low-traffic website, it might not be respawned at all. An incoming MSMQ message will not wake up the website; it will fall on deaf ears. (Of course, it’s probably possible to do an end run around this limitation with Windows Activation Services but that would probably be more trouble than it’s worth.)

This is why the MsmqTransport in a web application is usually configured to be non-transactional and to purge its input queue on startup, because normally, messages handled by a web application amount to “what you have in your cache is now wrong” which don’t apply to a web application just starting up that has nothing in cache.

The reason I consider this to be the lesser of the three reasons is because if you’re interested in creating enterprise systems with NServiceBus, you are probably operating a website that is fairly busy that won’t go idle and silent, however, it seems obvious that a Windows Service makes a much more appropriate host for a message publishing endpoint than a web application that may be spun down at any time.

Conclusion

Hopefully this clears up the confusion surrounding why it’s best not to publish NServiceBus events from a web application. Sure, the framework will technically let you do it, but it is to do as the FAQ says: don’t. Your reward: better, more fault-tolerant, more performant web applications that are easier to scale up and out.

Related Posts:

  • Pingback: Tweets that mention Why not publish NServiceBus messages from a web application? | David Boike's Blog -- Topsy.com

  • http://jonathan-oliver.blogspot.com Jonathan Oliver


    Great stuff! I especially liked your explanation about how we can turn web applications into semi-dumb facade. That’s exactly what web apps are supposed to be.

  • Pingback: NServiceBus Weekly: #13

  • Mitch Rosenburg


    So is “sending” an event to an application layer which will immediately “publish” the event preferable to publishing the event from the web app directly?

    I know neither is ideal, but the command logic in our case will still be in the web app, but I’d like to publish events so that processes who care can do something with them.

  • http://www.make-awesome.com David Boike


    I believe publishing from the web application is always, at the very least, extremely shortsighted.

    However, I think I would avoid “sending an event” (quoted because I contend commands are sent and events are published, by definition) and then relaying it by publishing the very same message.

    In order to minimize duplication, you could have a Command and Event inherit from a common base class with the shared fields, but they really should be different classes. The website can Send the Command to the service layer, which can translate the properties from the Command to the Event and then Publish the Event.

    At the very least, this minimizes confusion. It also prevents you from accidentally creating an infinite loop where your website “sends the event”, which the service layer publishes, only to have the web application accidentally subscribe to and handle!

  • http://uttamkini.wordpress.com/ Uttam Kini


    My thoughts on the three things that you pointed out
    1. Transactional scope on the publisher side…. This is very important, because if NServiceBus throws up during a Bus.Publish(), we need to handle that in the right way.

    2. You say that when scaling out (i.e. adding a new publisher node to our web farm), the subscriber needs to subscribe to this extra node as well (since it has it’s own input queue). This I disagree, since the subscription is per message (not per input queue) and the subscription information is stored in a central database location, scaling out should be trivial. i.e. a subscriber will do a Bus.Subscribe() to one of the nodes in my web farm. This gets stored in a database which is used by all other publisher nodes to decide who to publish their messages to.

    3. The last thing is that when IIS recycles it’s worker processes, NServiceBus may not come up. I would say that even after an app pool recycle, to publish a message we do a Bus.Send()/Bus.Publish() and this means that Bus would have been initialized. In the case of a publisher initialization means that I know all the people who subscribe to me when I wake up.

  • http://www.make-awesome.com David Boike


    On #2, this would not be possible because NServiceBus enforces only one subscription per message type, in order to enforce the SOA best practice of having one event type being completely owned by a logical service. Once you subscribe to Message1 at QueueName@WebServer1, you will not also be able to subscribe to Message1 coming from QueueName@WebServer2.

    On #3, your point isn’t totally clear to me. When NServiceBus is hosted within a web application (typically within the Global.asax) it is initialized on the application’s start event, so you don’t need to worry about the Bus not being initialized.

    As far as knowing about subscriptions to an event when a process “wakes up” this is not necessary – NServiceBus takes the safe approach (although with a performance penalty) of looking up the list of subscribers each and every time a message is published, without cache. Of course, in a high-performance scenario, you could replace the subscription storage component with your own implementation that employs caching, but then of course you’d need to deal with a scenario where a brand-new subscriber may not receive a message it is subscribed to until the cache expires.

  • Pingback: Recommended message bus architecture for publishing client events

  • Scott Coates


    Can someone simply explain the difference between publish vs send? I can’t find a clear-cut differentiation.

  • http://www.make-awesome.com David Boike


    When you Send a message, that can be thought of as a Command. It is sent from point A to point B, saying “Do something now.” If you’re following good SOA structure, this should only happen inside a logical service, because the sender must necessarily know a lot about the receiver because the sender is expecting the receiver to do something specific, like “Update this user’s email address.”

    When you Publish a message, that can be though of as an Event. It is published by point A and can be received by multiple (or zero!) subscribers. It is an announcement that “Something has happened. Do something if you feel like it, but I don’t care.” This is how logical services communicate with each other. The UserService says “A new user has registered with us.” and in response, an EmailService decides to send them a welcome email. The schema of the event messages that are published becomes the service’s contract with the outside world.

    Does that make the distinction clear?