beaucrawford.net

Give me data or give me death

About the author

Author Name is someone.
E-mail me Send mail

Recent comments

Don't show

Authors

Tags

Don't show

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2010

    MSMQ – Sending Messages to Remote Queues

    The situation is simple – you want to send a message to a remote MSMQ. To do so you might write some code that looks something like:

    using (var queue = new MessageQueue(@"FormatName:Direct=TCP:192.168.2.157\Private$\TheQueue"))
    {	
    	var message = new Message(shipment);
    	message.Formatter = new BinaryMessageFormatter();
    	queue.Send(message, MessageQueueTransactionType.Single);	
    }

    This code works fine... most of the time. The problem is that, for remote queues, MSMQ sends messages in a "fire and forget" type of mode by default, i.e. if the message gets there, great! If not, oh damn well. This was not apparent to me at first. In workflow situations where you cannot let things "slip through the cracks" it is critical that you receive acknowledgement of delivery. For example, consider the following pseudo-code:

    using (var transaction = new TransactionScope())
    {
        // Perform numerous database operations here
    
        // Send message to remote queue here
    
        transaction.Complete();
    }

    What if the send operation to the remote queue does not succeed? Well, in a workflow with state tracking, we absolutely must rollback all of the database operations and leave the system in the exact same state that existed before we attempted the send operation. The only way we can do this is to know whether the message arrived in the remote queue. Thankfully MSMQ provides a fairly easy way to accomplish this through the use of an Administrative Queue. The purpose of this queue is to provide a "callback" location for the target queue to send an acknowledgement message. This message is uniquely identified by its Message ID property. The high-level steps for guaranteed delivery are:

    1) Create a message and define an Administrative Queue 
    2) Send the message 
    3) Wait a little 
    4) Check the Administrative Queue for the message's unique ID

    The code to do this is:

    using (var queue = new MessageQueue(@"FormatName:Direct=TCP:192.168.2.157\Private$\TheQueue"))
    {
    	var message = new Message(shipment);
    	message.Formatter = new BinaryMessageFormatter();
    	message.AdministrationQueue = new MessageQueue(@"FormatName:Direct=TCP:192.168.2.148\Private$\AdminQueue");
    	message.AcknowledgeType = AcknowledgeTypes.PositiveArrival;
    	queue.Send(message, MessageQueueTransactionType.Single);
    
    	Thread.Sleep(100);
    
    	bool acknowledged = ReceiveAcknowledgment(message.Id, @".\Private$\AdminQueue");
    
    	if (!acknowledged)
    	{
    	   throw new InvalidOperationException("Acknowledgement was not received");
    	}
    }

    Yes, the above code uses a Thread.Sleep call. I realize that this is somewhat of an anti-pattern but it is called for here as you have no way of gauging network latency.  The best you can really do is supply a sleep time that is relative to your queue architecture, i.e. if your queues are on an Intranet then you can probably get away with 100 ms (or less).  If you’re using queues over the Internet then you will probably need a longer wait time.  This is the price you pay for guaranteed delivery acknowledgement – a small one in my opinion.

    The "ReceiveAcknowledgment" helper method is defined as follows:

    private static bool ReceiveAcknowledgment(string messageId, string queuePath)
    {
        var queue = new MessageQueue(queuePath);
        queue.MessageReadPropertyFilter.CorrelationId = true;
        queue.MessageReadPropertyFilter.Acknowledgment = true;
    
        while (queue.PeekByCorrelationId(messageId) != null)
    	{
    		Message message = queue.ReceiveByCorrelationId(messageId);
    		return true;
    	}
    
        return false;
    }

    Categories: C#
    Posted by Beau on Saturday, June 27, 2009 11:43 AM
    Permalink | Comments (1) | Post RSSRSS comment feed

    CoreDateTime.Now - The Future is Now

    Like most developers, I often find myself dealing with code that references DateTime.Now. For example consider this code that retrieves items relative to the current date/time:

    var command = new SqlCommand();
    command.CommandType = CommandType.StoredProcedure;
    command.CommandText = "GetItems";
    command.Parameters.Add(new SqlParameter("TargetDate", DateTime.Now));

    It would be hard to develop an integration test for this code since it references DateTime.Now. What if I wanted to test the scenario where items with a future date/time value needed to be retrieved, i.e. how will the system behave six months from now? A simple, but very effective, way to deal with this is to add the following class:

    public class CoreDateTime
    {
        static CoreDateTime()
        {
            Executor = () => DateTime.Now;
        }
    
        internal static Func Executor
        {
            get;
            set;
        }
    
        public static DateTime Now
        {
            get
            {
                return Executor();
            }
        }
    }

    The key thing to note here is that the "Executor" property is simply a Func that wraps a call to the normal DateTime.Now. This means that CoreDateTime.Now will behave exactly like DateTime.Now.

    You will also notice that the "Executor" property uses the internal access modifier. This allows testing assemblies to inject a Func of their choosing. You can expose this property to test assemblies using the System.Runtime.CompilerServices.InternalsVisibleTo assembly attribute and then update it with code like:

    CoreDateTime.Executor = () => DateTime.Parse("5/10/2013 10:15 AM");

    You can also have successive calls to CoreDateTime.Now be evaluated against a fixed point in time. This allows you to easily jump to any point of time in the past or future. This code might look like:

    var init = DateTime.Now;
    CoreDateTime.Executor = () => dateTimePicker1.Value.AddSeconds((DateTime.Now - init).TotalSeconds);                

    Happy time travels!


    Categories: C# | Testing
    Posted by Beau on Saturday, June 27, 2009 10:13 AM
    Permalink | Comments (0) | Post RSSRSS comment feed