Tuesday, 21 November 2017

NServiceBus ...


So while working for a well known Insurance company in Gloucester I was asked to build and document a service bus. After thrashing around with ReBus I convinced the client to go with NServiceBus - what a saga, turing a dramas into a saga...now!

NServiceBus is really a distributed messaging layer. It allows for all sorts of communications between processes, you can choose from:
                Peer to peer
                Pub/sub
                Send to self
                Broadcast to all

However at the end of the day what makes this all possible is the central backbone of NServiceBus.
These days NServiceBus also offers a cloud based offering. In this article I will however be focusing more on the regular NServiceBus installation, which is by using NServiceBus within an organization using MSMQ.

Transactional
This uses the standard Distributed Transaction Coordinator, to allow inter process transactions to occur. What the NServiceBus framework does is that it will only commit a Transaction when a message (or complete Saga) is completed. If an Exception is seen within a message handler, NServiceBus will possibly carry out n-many retries (you must configure this), after which it will roll back the transaction.

Durable
As NServiceBus uses MSMQ as a transport (or Azure, but as I stated we are not discussing that in this article). All messages are safe, and will be maintained even after the loss of power. The usual MSMQ benefits are available.

Reliable
This is partly achieved thanks to the use of MSMQ and also thanks to the fact that NServiceBus will persist things at various stages in its messaging pipeline. As previously stated this could use MSMQ/Raven or SQL storage. This article will talk about the use of SQL storage for persistence.

Distributed
The fact that we could distribute handlers/publishers across an entire network, allows us to completely distribute our messaging layer.

Scalable
NServiceBus provides a load balancer called "The Distributor". I will not be covering that in this article, but if you think you would like to load balance your messaging components, "The Distributor" may be for you.

Setup
As previously stated NServiceBus provides a common messaging layer interface for the demo app we will be looking at using NServiceBus to accept a Command and then use a Message.
This diagram may help to illustrate this further.

It can be seen that NServiceBus provides the common messaging layer backbone (for want of a better word) and that each of the processes that deals with the messages (known as an endpoint in NSB speak) has a MSMQ. It is important to note that this is only one possible configuration of how to use NServiceBus. You really can configure it to suit your needs. The above diagram is just how I chose to do it for the demo app.

Messages
It is fair to say that NServiceBus is all about the messages. If you want to send a command or an event to a NServiceBus endpoint, it will take the form of a message. So what exactly is a message? Put simply it is a shared contract that all parties know how to deal with. The messages are serialized by NServiceBus into the serialization format you choose (There are many choices here Xml, Json, Bson, Binary etc, etc), and deserialized by the endpoint(s) that deal with the messages (via the use of configuration and the expected handlers). If you come from a WCF world, you can think of messages as the objects that are shared between client and server.

[DataContract]

There is a distinction between "Command" messages and "Message" messages, but we will discuss this later. For now let's just see an example of the code for both.

Command
namespace Messages.Commands
{  
   public class CreatePurchaseOrderCommand
   {
        public int PurchaseOrderId { get; set; }
        public string Description { get; set; }
    }
}

Message
namespace Messages.Message
{
    public class CheckPurchaseOrderStatusMessage
    {
        public int PurchaseOrderId { get; set; }
        public string ConfirmationDescription { get; set; }
    }
}
As you can see the Command and Message classes are just standard .NET classes, nothing special about them at all. We will get to the bit where we discuss the importance between Commands and Message, but for now just note that these messages are just regular .NET classes that allow you to add whatever data you want to them. You can be reassured that NServiceBus will make sure that the values for these messages will be stored when needed.

Commands Vs Messages
Ok so what exactly is the difference between a command and a message. Well to understand that a bit further, let's consider the following scenario.
We wish to design an ordering system something like Amazon, where we allow the user to place an order. When an order is placed by the customer it should be dispatched and email is sent to the client notifying them of the purchase.

OR
Command => DoSomething (multiple senders, single receiver)
Event => SomethingHasBeenDone (single sender, multiple receivers)
Message => request/response (base class of other 2)


Now that is a pretty simple workflow, but how do "Commands" and "Messages" fit into that?
Well if we break it down we can imagine something like the following:
Action                                                    Command Or Message?
Place order                                           Command to start the work flow
Dispatch order                                     Message that could advance the workflow
Email client order confirmation        Message that could advance the workflow

Still not clear?

Ok so let's try some words. I find it helps to think of things as follows:
Command : Is something that is about to happen. Typically this would be a 1..1 type of message.
Message : Something that may continue the current long running process. This would typically be sent the current endpoint, and would more than likely be a 1..1 type of message.

NOTE : The more eagle eyed amongst you may think that rather than having one big workflow we could possibly have multiple endpoints, one for DispatchOrder, and another for EmailConfirmationToClient. The difference being is that if you chose to go down this route, you would need to send a message to a new endpoint rather than locally
NServiceBus also supports the idea of publishing events, this would typically be used when you want more than one endpoint to act on some event. In fact it should come as no surprise that NServiceBus distinguishes this type of message as an "Event" that is broadcast (via Bus.Publish(...)) to all interested endpoints. This is not done in the demo app, but rest assured it is completely possible, and is easily achieved by using

NServiceBus. Thing is at the end of the day this is an architectural decision that only you can make.
More information of messaging type distinctions can be found at NServiceBus web site.
These web sites will give the types of message patterns used as a defacto.
http://www.enterpriseintegrationpatterns.com/patterns/messaging/EventMessage.html
http://www.enterpriseintegrationpatterns.com/patterns/messaging/CommandMessage.html

Hosting The Bus
NServiceBus offers a few hosting solutions, you may choose from:
1). Running the standalone NServiceBus.Host.exe executable.
2). Hosting NServiceBus inside a windows service, which just runs the standalone NServiceBus.Host.exe executable.
3).Completely self hosted.

Sagas
Long-running business processes exist in many systems. Whether the steps are automated, manual, or a combination, effective handling of these processes is critical. NServiceBus employs event-driven architectural principles to bake fault-tolerance and scalability into these processes. The saga is a pattern that addresses the challenges uncovered by the relational database community years ago, packaged in NServiceBus for ease of use. One of the common mistakes developers make when designing distributed systems is based on the assumptions that time is constant. If something runs quickly on their machine, they're liable to assume it will run with a similar performance characteristic when in production. Network invocations (like web service calls) are misleading this way. When invoked on the developer's local machine, they perform well. In production, across firewalls and data centres, they don't perform nearly as well. While a single web service invocation need not be considered "long-running", once there are two or more calls within a given use case, take issues of consistency into account. The first call may be successful but the second call can time out. Sagas allow coding for these cases in a simple and robust fashion. Design processes with more than one remote call to use sagas. While it may seem excessive at first, the business implications of the system getting out of sync with the other systems it interacts with can be substantial. It's not just about exceptions that end up in the logs.

My Implementation:
We have a simple console app with a service base inherited into the program class to all us to perform the start-up of the process.  As per the following code sample:
(Full project resides in Presto.ESB.SagaTemplate)
using NServiceBus;
using NServiceBus.Logging;
using NServiceBus.Serilog;
using Serilog;
using SimpleInjector;
using SimpleInjector.Lifestyles;
using System;
using System.ComponentModel;
using System.ServiceProcess;
using System.Threading.Tasks;
using Container = SimpleInjector.Container;

namespace Mikeys.ESB.SagaTemplate
{
    /// <br />
<summary>
    /// Used by NServiceBus DO NOT REMOVE
    /// </summary>
    /// <seealso cref="System.ServiceProcess.ServiceBase">
    [DesignerCategory("Code")]
    public class ProgramService : ServiceBase
    {
        /// <summary>
        /// The endpoint instance for the current Saga Service
        /// </summary>
        private static IEndpointInstance _endpointInstance;
        /// <summary>
        /// The logger writes to log file, all information and errors
        /// </summary>
        private static readonly ILog Logger;

        /// <summary>
        /// Initializes the <see cref="ProgramService"> class.
        /// </see></summary>
        static ProgramService()
        {
            // Configure container.
            var containerForIoc = new Container();
            containerForIoc.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
            containerForIoc.Register<inservicemessagehub nservicemessagehub="">(Lifestyle.Singleton);
            containerForIoc.Register<sharedjobservice sharedjobservice="">(Lifestyle.Singleton);
            containerForIoc.Verify();

            // Configure logging.
            Log.Logger = new LoggerConfiguration().WriteTo.ColoredConsole().WriteTo.RollingFile(@"c:\\Presto\\logs\\Log -{Date}.log").CreateLogger();
            LogManager.Use<serilogfactory>();
            Logger = LogManager.GetLogger<serilogfactory>();
        }

        /// <summary>
        /// Defines the entry point of the application.
        /// </summary>
        public static void Main()
        {
            using (var service = new ProgramService())
            {
                Logger.Info("Configuring service.");

                Console.Title = "SagaTemplate Console Application";
                // To run interactive from a console or as a windows service
                if (Environment.UserInteractive)
                {
                    Console.CancelKeyPress += (sender, e) =&gt;
                    {
                        service.OnStop();
                    };
                    service.OnStart(null);
                    Console.WriteLine("\r\nPress enter key to stop program\r\n");
                    Console.Read();
                    service.OnStop();
                    return;
                }
                Run(service);
            }
        }

        /// <summary>
        /// When implemented in a derived class, executes when a Start command is sent to the service by the Service Control Manager (SCM)
        /// or when the operating system starts (for a service that starts automatically). Specifies actions to take when the service starts.
        /// </summary>
        /// <param name="args" />Data passed by the start command.
        protected override void OnStart(string[] args) =&gt; AsyncOnStart().GetAwaiter().GetResult();

        /// <summary>
        /// Asynchronous the on start.
        /// </summary>
        /// <returns></returns>
        private static async Task AsyncOnStart()
        {
            try
            {
                var endpointConfiguration = new EndpointConfiguration("SagaTemplate");
                NServiceMessageHub.EndPointConfiguration(endpointConfiguration);
                _endpointInstance = await Endpoint.Start(endpointConfiguration).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                Logger.Fatal("Failed to start", exception);
                Environment.FailFast("Failed to start", exception);
            }
        }

        /// <summary>
        /// When implemented in a derived class, executes when a Stop command is sent to the service by the Service Control Manager (SCM).
        /// Specifies actions to take when a service stops running.
        /// </summary>
        protected override void OnStop() =&gt; _endpointInstance?.Stop().GetAwaiter().GetResult();
    }
}

The Saga processing for this is processed by the ProcessOrderSaga class (plus same named interface) with its own model ProcessOrderSagaData both these classes are for education and can be cloned and used by the developer. The bulk of the models will live in the Presto.ESB.Messages. These will define commands, events and messages and all such models. Being suffixed in the name for the appropriate type.

public class DispatchOrderCommand : ICommand
public interface IOrderActivityEvent : IEvent
public interface IOrderDispatchedMessage : IMessage

</serilogfactory></serilogfactory></sharedjobservice></inservicemessagehub></seealso>