Software Design Blog - Design Patterns Simple solutions to solve complex problems / http://www.rssboard.org/rss-specification BlogEngine.NET 3.1.1.0 en-US /opml.axd http://www.dotnetblogengine.net/syndication.axd Jay Strydom Software Design Blog 0.000000 0.000000 A step-by-step guide to detect errors and retry operations <img class="img-responsive" src="/pics/banners/ImproveReliabilityBlog.jpg"> <br> <p> We are liable for the reliability of our apps, which work when tested but fail in production environments due to unexpected temporary conditions. Errors can occur due to an intermittent service, infrastructure fault, network issue or explicit throttling. If the operation is retried a short time later (maybe a few milliseconds later) the operation may succeed. </p> <p>A lazy brain can quickly solve this problem without a lot of planning, flexibility or configuration in mind as shown in this <a href="https://msdn.microsoft.com/en-us/library/system.net.mail.smtpexception(v=vs.110).aspx#Anchor_8" target="_blank">MSDN sample</a> that performs a retry when the SMTP mail client fails.</p> <pre class="brush: c-sharp;"> try { client.Send(message); } catch (SmtpFailedRecipientsException ex) { for (int i = 0; i &lt; ex.InnerExceptions.Length; i++) { SmtpStatusCode status = ex.InnerExceptions[i].StatusCode; if (status == SmtpStatusCode.MailboxBusy || status == SmtpStatusCode.MailboxUnavailable) { System.Threading.Thread.Sleep(5000); client.Send(message); } } } </pre> <div class="alert alert-warning" role="alert"> <b>Warning!</b> Bad code, do not copy. </div> <p><b>The problem</b> is how do you retry a failed operation correctly?</p> <p><b>The solution</b> is to create an error detection strategy to determine if the error can be retried and use a retry policy to define the number of retries and frequency between retries.</p> <p>This post extends the <a href="/post/step-by-step-guide-to-use-dependency-injection">previous example</a> by adding retry logic to the SMTP Mail Client. The aim is to illustrate how to improve the reliability of an app by making it more robust.</p> <div class="alert alert-info" role="alert"> <b>Note:</b> The approach used in this post is generic and can be applied to database repositories, cloud services, web services and more. </div> <a class="btn btn-primary btn-sm" role="button" href="/Downloads/OrderApplicationRetry.zip">Download Source Code</a> <h3>Retry Solution - Done Properly</h3> <p>Let’s get started by implementing clean retry code in 4 easy steps.</p> <h5>Step 1 – Add the transient fault handling NuGet package</h5> <p>The Microsoft transient fault handling NuGet package contains generic, reusable and testable components that we will use for solving the SMTP mail client retry problem.</p> <p>Add the <a href="https://www.nuget.org/packages/EnterpriseLibrary.TransientFaultHandling/" target="_blank">EnterpriseLibrary.TransientFaultHandling</a> NuGet package to the Orders.Implementation project.</p> <h5>Step 2 – Create a transient error detection strategy</h5> <p>Transient (temporarily) faults are errors that can be retried. Here are a few examples of transient errors that may work if retried:</p> <ul> <li>The host is not responding or is unavailable</li> <li>The server is busy or the connection was dropped</li> </ul> <p>Here are a few examples of permanent errors that won’t work even if retried:</p> <ul> <li>Authentication failed (invalid username or password)</li> <li>Bad request (invalid email address, attachment not found)</li> </ul> <p>Let’s create a detection strategy that will detect SMTP Mail errors that can be retried.</p> <pre class="brush: c-sharp;"> public class SmtpMailErrorDetectionStrategy : ITransientErrorDetectionStrategy { public bool IsTransient(Exception ex) { var smtpFailedException = ex as SmtpFailedRecipientsException; if (smtpFailedException == null) return false; return smtpFailedException.InnerExceptions .Any(mailEx =&gt; mailEx.StatusCode == SmtpStatusCode.MailboxBusy || mailEx.StatusCode == SmtpStatusCode.MailboxUnavailable); } } </pre> <h5>Step 3 – Create the SMTP Retry Decorator</h5> <p>Based on to the single responsibility principle (SRP), the mail client should only be responsible for one thing, which is sending mail. Adding error detection and retry logic violates the SRP since it shouldn't be it's problem.</p> <p>The decorator pattern is great for extending an existing class. Just imagine how large the class will become if we continually add cross-cutting functionality to it such as retries, logging and performance monitoring.</p> <p>Here is the existing SMTP mail client used in the <a href="/post/step-by-step-guide-to-use-dependency-injection">previous post</a>:</p> <img class="img-responsive" src="/pics/blogs/EmailServiceFailure.png"> <br> <p>We are going to decorate the SMTP mail client with a retry mail client decorator as shown below:</p> <img class="img-responsive" src="/pics/blogs/EmailServiceFailureRetry.png"> <pre class="brush: c-sharp;"> public class SmtpMailClientRetryDecorator : IMailClient { private readonly IMailClient _next; private readonly RetryPolicy _retryPolicy; public SmtpMailClientRetryDecorator(IMailClient next, RetryPolicy retryPolicy) { if (next == null) throw new ArgumentNullException("next"); if (retryPolicy == null) throw new ArgumentNullException("retryPolicy"); _next = next; _retryPolicy = retryPolicy; } public void Send(string to, string subject, string body) { _retryPolicy.ExecuteAction(() =&gt; _next.Send(to, subject, body)); } } </pre> <h5>Step 4 – Compose the Solution</h5> <p>The transient fault handling library provides the following retry strategies:</p> <table class="table table-bordered"> <tbody><tr><th> <p>Retry strategy</p> </th><th> <p>Example (intervals between retries in seconds)</p> </th></tr> <tr><td data-th=" Retry strategy "> <p>Fixed interval</p> </td><td data-th=" Example (intervals between retries in seconds) "> <p>2,2,2,2,2,2</p> </td></tr> <tr><td data-th=" Retry strategy "> <p>Incremental intervals</p> </td><td data-th=" Example (intervals between retries in seconds) "> <p>2,4,6,8,10,12</p> </td></tr> <tr><td data-th=" Retry strategy "> <p>Random exponential back-off intervals</p> </td><td data-th=" Example (intervals between retries in seconds) "> <p>2, 3.755, 9.176, 14.306, 31.895</p> </td></tr> </tbody></table> <p>Let’s register the fixed interval retry strategy in the Unity IoC container as shown below. If you are new to Dependency Injection (DI), <a href="/post/step-by-step-guide-to-use-dependency-injection">read this post</a>.</p> <pre class="brush: c-sharp;"> // This should be defined in app settings const int maxRetries = 5; var retryInterval = TimeSpan.FromSeconds(2); _container.RegisterType&lt;FixedInterval&gt;( new InjectionConstructor(maxRetries, retryInterval)); _container.RegisterType&lt;RetryPolicy&lt;SmtpMailErrorDetectionStrategy&gt;&gt;( new InjectionConstructor(new ResolvedParameter&lt;FixedInterval&gt;())); _container.RegisterType&lt;IMailClient, SmtpMailClient&gt;(typeof(SmtpMailClient).FullName); _container.RegisterType&lt;IMailClient, SmtpMailClientRetryDecorator&gt;( new InjectionConstructor( new ResolvedParameter&lt;IMailClient&gt;(typeof(SmtpMailClient).FullName), </pre> <div class="alert alert-success" role="alert"> <b>Success!</b> We have added a flexible retry solution to our app. </div> <p>And for those who may think this is over-engineered and too complicated then this is how you can construct the retry policy in the SMTP mailer class – but of course you will run in to the problems discussed in earlier posts!</p> <pre class="brush: c-sharp;"> const int maxRetries = 5; var retryInterval = TimeSpan.FromSeconds(2); var policy = new RetryPolicy&lt;SmtpMailErrorDetectionStrategy&gt;( new FixedInterval(maxRetries, retryInterval)); policy.ExecuteAction(() =&gt; client.Send(mesage)); </pre> <h3>Summary</h3> <p>This post showed how to implement a flexible, configurable solution using the <a href="https://msdn.microsoft.com/en-us/library/dn440719(v=pandp.60).aspx" target="_blank">Microsoft Transient Fault Handling Application Block</a> to retry transient failures in order to improve app reliability.</p> <p>If we refer to the original <a href="https://msdn.microsoft.com/en-us/library/system.net.mail.smtpexception(v=vs.110).aspx#Anchor_8" target="_blank">MSDN code sample</a>, we can see a similar pattern by evaluating specific transient error codes (<i>transient error detection strategy</i>), pausing for 5 seconds (<i>retry policy - retry Interval</i>) and retrying the send operation once (<i>retry policy - retry count</i>).</p> /post/a-step-by-step-guide-to-detect-errors-and-retry-operations jay@webdevelopment.co.nz /post/a-step-by-step-guide-to-detect-errors-and-retry-operations#comment /post.aspx?id=6459fc61-6209-44fb-aa9e-773cfc1cba21 Tue, 26 Jan 2016 21:35:00 +1300 Dependency Injection Design Patterns Decorator Pattern .NET C# Jay Strydom /pingback.axd /post.aspx?id=6459fc61-6209-44fb-aa9e-773cfc1cba21 0 /trackback.axd?id=6459fc61-6209-44fb-aa9e-773cfc1cba21 /post/a-step-by-step-guide-to-detect-errors-and-retry-operations#comment /syndication.axd?post=6459fc61-6209-44fb-aa9e-773cfc1cba21 Kill the switch with the strategy pattern <img class="img-responsive" alt="Chain of Responsibility" src="/pics/banners/StrategyPatternBlog.jpg"> <br> <p> The <a href="/post/problem-solving-beyond-the-basics">previous post</a> described the challenge of validating credit card numbers based on the credit card type such as visa or master card. Many if conditional checks were performed which was improved using the switch statement. </p> <h5>Why was the switch statement bad?</h5> <p>Let's say you have 5 cases and 10 lines each.</p> <ul> <li>What if we had to add, remove or modify a case? The class has 7 reasons to change, which violates the open/close principle.</li> <li>At least 5 tests are required to test each case. The class does 5 things, so it violates the single responsibility principle.</li> <li>The class is at least 50 lines long without the possibility of reusing anything.</li> </ul> <p> This post will provide an illustration of using the strategy design pattern with table control flow to replace the switch statement. </p> <p><b>The problem</b> is how we can define a family of algorithms (credit card validators), encapsulate each one, and make them interchangeable?</p> <p><b>The solution</b> is to use the strategy design pattern that allows the algorithm to vary independently from clients that use it.</p> <a class="btn btn-primary btn-sm" role="button" href="/Downloads/TableFlowStrategyPattern.zip">Download Source Code</a> <h3>Setup</h3> The following classes from the <a href="/post/problem-solving-beyond-the-basics">previous post</a> will be reused. <pre class="brush: c-sharp;"> public class CreditCard { public string Type { get; set; } public string Name { get; set; } public string Number { get; set; } public string Expiry { get; set; } } public interface ICreditCardValidator { void Validate(CreditCard creditCard); } </pre> <h3>Strategy Pattern</h3> <p>Let's get started with the strategy pattern in 5 easy steps.</p> <h5>1. Specify the signature for the algorithm in an interface</h5> <p>We need to validate a credit card number so we need a method that takes a number as shown below.</p> <pre class="brush: c-sharp;"> public interface ICreditCardNumberValidator { void Validate(string number); } </pre> <h5>2. Bury the algorithm implementation details in derived classes</h5> <p>Each credit card validator implementation can be different. In this example, all credit card validators will use a regular expression so we only need one class.</p> <pre class="brush: c-sharp;"> public class RegExCreditCardNumberValidator : ICreditCardNumberValidator { private readonly Regex _regex; public RegExCreditCardNumberValidator(Regex regex) { if (regex == null) throw new ArgumentNullException("regex"); _regex = regex; } public void Validate(string number) { if (!_regex.IsMatch(number)) throw new InvalidCreditCardException(); } } </pre> <p>A new instance of the class will be created for each credit card type. For example:</p> <pre class="brush: c-sharp;"> var visaRegEx = new Regex("^4[0-9]{6,}$", RegexOptions.Compiled); var visaValidator = new RegExCreditCardNumberValidator(visaRegEx); </pre> <h5>3. Identify an algorithm that the client would prefer to access</h5> <p>The credit card validation algorithm is based on the credit card type. The credit card type is supplied in the credit card model/DTO. Therefore, we can perform an algorithm lookup based on the credit card type.</p> <p>A dictionary is great way to perform a lookup, where the key represents the credit card type and the value represents the validator.</p> <pre class="brush: c-sharp;"> var strategies = new Dictionary&lt;string, ICreditCardNumberValidator&gt; (StringComparer.OrdinalIgnoreCase); </pre> <div class="alert alert-success" role="alert"> <b>Solved!</b> The dictionary key lookup is set to case insensitive. The problem of comparing strings or calling .ToLower() in the Switch solution disappears. </div> <p>The strategy validator is shown below.</p> <pre class="brush: c-sharp;"> public class CreditCardValidatorStrategy : ICreditCardValidator { private readonly IDictionary&lt;string, ICreditCardNumberValidator&gt; _strategies; public CreditCardValidatorStrategy( IDictionary&lt;string, ICreditCardNumberValidator&gt; strategies) { if (strategies == null) throw new ArgumentNullException("strategies"); _strategies = strategies; } public void Validate(CreditCard creditCard) { if (creditCard == null) throw new ArgumentNullException("creditCard"); if (string.IsNullOrWhiteSpace(creditCard.Type)) throw new ArgumentException(Resource.MissingCreditCardType); if (!_strategies.ContainsKey(creditCard.Type)) throw new InvalidCardException( string.Format(Resource.UnsupportedCreditCard, creditCard.Type)); _strategies[creditCard.Type].Validate(creditCard.Number); } } </pre> <div class="alert alert-success" role="alert"> <b>Solved!</b> The validator class is agnostic of the credit card validation implementation and doesn't need to be modified in order to support additional credit cards. </div> <h5>4. Building the table control lookup</h5> <p>We can build the dictionary lookup table based on a repository such as a database or a configuration file.</p> <p>The credit card types and regular expressions are defined in the App.config as shown below.</p> <pre class="brush: xml;"> &lt;?xml version="1.0" encoding="utf-8" ?&gt; &lt;configuration&gt; &lt;configSections&gt; &lt;section name="creditcardnumberexpressions" type="System.Configuration.DictionarySectionHandler" /&gt; &lt;/configSections&gt; &lt;creditcardnumberexpressions&gt; &lt;add key="visa" value="^4[0-9]{6,}$" /&gt; &lt;add key="mastercard" value="^5[1-5][0-9]{5,}$" /&gt; &lt;/creditcardnumberexpressions&gt; &lt;/configuration&gt; </pre> <p>We can compose the dictionary of strategies from the App.config as shown below.</p> <pre class="brush: c-sharp;"> public class ConfigDictionaryLoader : ISettingsLoader { private readonly string _sectionName; public ConfigDictionaryLoader(string sectionName) { if (sectionName == null) throw new ArgumentNullException("sectionName"); _sectionName = sectionName; } public IDictionary&lt;string, string&gt; Load() { var settings = ConfigurationManager.GetSection(_sectionName) as Hashtable; if (settings == null) { throw new Exception(string.Format(Resource.MissingConfig, _sectionName)); } return settings.Cast&lt;DictionaryEntry&gt;() .ToDictionary(n =&gt; n.Key.ToString(), n =&gt; n.Value.ToString()); } } public class CreditCardValidatorFactory : ICreditCardValidatorFactory { private readonly ISettingsLoader _loader; public CreditCardValidatorFactory(ISettingsLoader loader) { if (loader == null) throw new ArgumentNullException("loader"); _loader = loader; } public IDictionary&lt;string, ICreditCardNumberValidator&gt; CreateStrategies() { var cardPairs = _loader.Load(); var strategies = new Dictionary&lt;string, ICreditCardNumberValidator&gt; (StringComparer.OrdinalIgnoreCase); foreach (var pair in cardPairs) { var regEx = new Regex(pair.Value, RegexOptions.Compiled); strategies[pair.Key] = new RegExCreditCardNumberValidator(regEx); } return strategies; } } </pre> <div class="alert alert-success" role="alert"> <b>Solved!</b> The solution in the previous post required a new build to add, remove or modify an algorithm. This problem disappears since values are loaded at run time. </div> <h5>5. Running the solution</h5> The entire solution is wired up as shown below. <pre class="brush: c-sharp;"> var configLoader = new ConfigDictionaryLoader("creditcardnumberexpressions"); var creditCardFactory = new CreditCardValidatorFactory(configLoader); var strategies = creditCardFactory.CreateStrategies(); var validator = new CreditCardValidatorStrategy(strategies); var creditCard = new CreditCard() { Type = "ViSa", Number = "4111111111111111" }; validator.Validate(creditCard); </pre> <h3>Summary</h3> <p>The strategy pattern provides a great alternative to the switch statement.</p> <p>The advantages of the strategy design pattern are:</p> <ul> <li>Reduces long lists of conditions such as If and Switch statements</li> <li>Avoids duplicate code</li> <li>Changes in one class does not require changes in other classes</li> <li>The Open-close principle is achieved since the class is open for extension but closed for modification</li> <li>The Single responsibility principle is achieved since the complexity is encapsulated per strategy</li> <li>Unit testing is simplified since each strategy can be tested in isolation</li> </ul> /post/kill-the-switch-with-the-strategy-pattern jay@webdevelopment.co.nz /post/kill-the-switch-with-the-strategy-pattern#comment /post.aspx?id=9202b6aa-9f69-4bd3-9e02-c69136d7e7c4 Mon, 11 Jan 2016 15:52:00 +1300 Design Patterns Strategy Pattern .NET C# Jay Strydom /pingback.axd /post.aspx?id=9202b6aa-9f69-4bd3-9e02-c69136d7e7c4 1 /trackback.axd?id=9202b6aa-9f69-4bd3-9e02-c69136d7e7c4 /post/kill-the-switch-with-the-strategy-pattern#comment /syndication.axd?post=9202b6aa-9f69-4bd3-9e02-c69136d7e7c4 Message Queue Delivery Strategies <img src="/pics/banners/AdvancedMSMQBlog.jpg" class="img-responsive" alt="Message Queue Delivery Strategies"> <br> <p>The previous post focused on <a href="/post/how-to-get-started-with-microsoft-message-queuing-msmq">MSMQ fundamentals</a> using a <b>pull</b> approach to retrieve messages from a queue.</p> <p>This post is the start of a series that covers multiple strategies to <b>push</b> queued messages to clients. The intention of the push approach is to keep clients agnostic of being part of a message based architecture.</p> <p>MSMQ technology is used but it is easy enough to change the implementation to use an alternative queuing solution such as Azure Service Bus.</p> <a href="/Downloads/MessageQueueSingleDelivery.zip" role="button" class="btn btn-primary btn-sm">Download Source Code</a> <h3>Setup</h3> <p>Setting up an MSQM was covered in the <a href="/post/how-to-get-started-with-microsoft-message-queuing-msmq">MSMQ fundamentals</a> post.</p> <p>The following code was used for placing 3 unique OrderModel messages in the queue.</p> <pre class="brush: c-sharp;"> [Serializable] public class OrderModel { public int Id { get; set; } public string Name { get; set; } } using (var queue = new MessageQueue(@".\Private$\Orders")) { queue.Formatter = new BinaryMessageFormatter(); for (var orderId = 1; orderId &lt;= 3; orderId++) { var order = new OrderModel() { Id = orderId, Name = string.Format("Order {0}", orderId) }; queue.Send(order); } } </pre> <h3>Command Pattern</h3> <p><b>The problem</b> is how can a message infrastructure issue requests to objects without knowing anything about the operation being requested or the receiver of the request?</p> <p><b>The solution</b> is to use the command pattern to decouple senders from receivers. A command decouples the object that invokes the operation from the object that knows how to perform the operation.</p> <p>The generic command interface is displayed below. The OrderProcessorCommand class implements the command interface to indicate that it can accept OrderModel messages, which it will use to simulate an order being processed.</p> <pre class="brush: c-sharp;"> public interface ICommand&lt;in T&gt; { void Execute(T message); } public class OrderProcessorCommand : ICommand&lt;OrderModel&gt; { private readonly int _id; public OrderProcessorCommand(int id) { _id = id; } public void Execute(OrderModel message) { if (message == null) throw new ArgumentNullException("message"); var start = DateTime.Now; // Simulate work being performed Thread.Sleep(TimeSpan.FromSeconds(2)); Console.WriteLine("Processed {0} by worker {1} from {2} to {3}", message.Name, _id, start.ToString("h:mm:ss"), DateTime.Now.ToString("h:mm:ss")); } } </pre> Note that a sleep was added on line 21 to simulate work being performed by the processor. <h3>Queue Monitor</h3> <p>The queue monitor class acts as orchestrator, which is responsible for listening to the queue for incoming messages and calling a command to execute each message.</p> <p>When the client calls the start method then the workflow outlined below will run consciously until the client calls the stop method:</p> <ol> <li>The BeginReceive method will kick off the queue listing operation.</li> <li>The OnReceiveComplete event will be raised when a message arrives.</li> <li>The command will be executed by passing in the message content.</li> </ol> <pre class="brush: c-sharp;"> public interface IQueueMonitor : IDisposable { void Start(); void Stop(); } public class QueueMonitor&lt;T&gt; : IQueueMonitor { private readonly MessageQueue _queue; private readonly ICommand&lt;T&gt; _command; private bool _continue = true; public QueueMonitor(MessageQueue queue, ICommand&lt;T&gt; command) { if (queue == null) throw new ArgumentNullException("queue"); if (command == null) throw new ArgumentNullException("command"); _queue = queue; _command = command; _queue.ReceiveCompleted += OnReceiveCompleted; } private void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs receiveCompletedEventArgs) { var message = _queue.EndReceive(receiveCompletedEventArgs.AsyncResult); _command.Execute((T)message.Body); if (_continue) _queue.BeginReceive(); } public void Start() { _continue = true; _queue.BeginReceive(); } public void Stop() { _continue = false; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool isDisposing) { if (!isDisposing || _queue == null) return; _queue.ReceiveCompleted -= OnReceiveCompleted; _queue.Dispose(); } } </pre> <div class="alert alert-info" role="alert"> <b>Note:</b> The push method will not overwhelm the client with requests. The queue monitor will be blocked on line 27 and will not retrieve the next message in the queue until the command has finished processing the current request. </div> <h3>Single Receiver</h3> <p>Let's see the gears ticking over by processing the messages on the queue.</p> <pre class="brush: c-sharp;"> using (var queue = new MessageQueue(@".\Private$\Orders")) { var command = new OrderProcessorCommand(1); var queueMonitor = new QueueMonitor&lt;OrderModel&gt;(queue, command); queueMonitor.Start(); } </pre> <pre>Processed Order 1 by worker 1 from 6:20:11 to 6:20:13 Processed Order 2 by worker 1 from 6:20:13 to 6:20:15 Processed Order 3 by worker 1 from 6:20:15 to 6:20:17 </pre> <p>The output above shows that the single receiver processed the messages in order, one at a time.</p> <p><b>The drawback</b> of the single receiver is the finite amount of throughput due to the constraint of processing one message at time.</p> <h3>Summary</h3> <p> This post demonstrated a generic approach to continually monitor a queue for new messages and pushing the message content to a command to execute. </p> <p>The next post will describe how to <a href="/post/broadcasting-messages-using-the-composite-pattern">broadcast a single message across multiple processors</a>.</p> /post/message-queue-delivery-strategies jay@webdevelopment.co.nz /post/message-queue-delivery-strategies#comment /post.aspx?id=b1aa59bc-113f-49bf-8efa-065c0e72b4b4 Mon, 21 Dec 2015 23:33:00 +1300 Design Patterns Command Pattern Software Architecture Queues Queues Design Patterns Command Pattern Jay Strydom /pingback.axd /post.aspx?id=b1aa59bc-113f-49bf-8efa-065c0e72b4b4 0 /trackback.axd?id=b1aa59bc-113f-49bf-8efa-065c0e72b4b4 /post/message-queue-delivery-strategies#comment /syndication.axd?post=b1aa59bc-113f-49bf-8efa-065c0e72b4b4