Software Design Blog - Decorator Pattern 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 [email protected] /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 Push queue processing boundaries with 3x greater throughput <img class="img-responsive" alt="Broadcasting Messages" src="/pics/banners/ProcessingQueuesFasterBlog.jpg"> <br> <p><b>The problem</b> is how can we measure the queue processing throughput? Or in a production environment, how can we add a performance counter without modifying our existing infrastructure?</p> <p><b>The solution</b> is to add a decorator pattern that will act as a proxy between the QueueMonitor class and the actual command processing class to intercept the communication and add instrumentation.</p> <p>The <a href="/post/dispatching-messages-with-the-competing-consumers-pattern">previous post</a> used the competing consumer pattern to process a queue concurrently. The <a href="/post/message-queue-delivery-strategies">message queue strategies</a> post used a single processor to process a queue.</p> <p>In this post, we will add instrumentation to the single queue processor and the competing consumer queue processor to compare performance.</p> <a class="btn btn-primary btn-sm" role="button" href="/Downloads/MessageQueueExamplePerformance.zip">Download Source Code</a> <h3>Setup</h3> <p>The experiment will add 512KB messages to a queue to simulate a decent workload. The intention is to read the messages from the queue and call a File SMTP mailer server that will write the emails to disk as fast as possible.</p> <p>The core components such as the Queue Monitor were covered in the <a href="/post/message-queue-delivery-strategies">Message Queue Delivery Strategies</a> post. The queue monitor is responsible for reading messages from the queue and pushing the message content to a command to execute.</p> <p>The classes that will be used in this experiment are listed below.</p> <pre class="brush: c-sharp;"> public class FileSmtpMailer : IMailer { private readonly string _path; public FileSmtpMailer(string path) { if (path == null) throw new ArgumentNullException("path"); _path = path; } public void Send(string message, string sender, string recipients, string subject) { using (var client = new SmtpClient()) { // This can be configured in the app.config client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory; client.PickupDirectoryLocation = _path; using (var mailMessage = new MailMessage(sender, recipients, subject, message)) { mailMessage.IsBodyHtml = true; client.Send(mailMessage); } } } } public class MailProcessorCommand : ICommand&lt;OrderMessage&gt; { private readonly IMailer _mailer; public MailProcessorCommand(IMailer mailer) { if (mailer == null) throw new ArgumentNullException("mailer"); _mailer = mailer; } public void Execute(OrderMessage message) { if (message == null) throw new ArgumentNullException("message"); _mailer.Send(message.Body, message.Sender, message.Recipients, message.Subject); } } </pre> <h3>Instrumentation</h3> <p>The TimerCommandDecorator decorator will be placed in between the QueueMonitor and the MailProcessorComamnd in order to measure the performance throughput. </p> <pre class="brush: c-sharp;"> public class TimerCommandDecorator&lt;T&gt; : ICommand&lt;T&gt; { private readonly ICommand&lt;T&gt; _next; private int _messages; private Stopwatch _stopwatch; public TimerCommandDecorator(ICommand&lt;T&gt; next) { if (next == null) throw new ArgumentNullException("next"); _next = next; } public void Execute(T message) { if (_stopwatch == null) _stopwatch = Stopwatch.StartNew(); _next.Execute(message); _messages += 1; Console.WriteLine("Processing {0} messages took {1} sec", _messages, _stopwatch.Elapsed.TotalSeconds); } } </pre> <p>The TimerCommandDecorator implementation can easily be swapped out with a perfmon version that will increment the performance counter for each message.</p> <h3>Single vs Competing Consumers</h3> <p>Let's run the experiment by observing the throughput difference between the single processor and competing consumer receivers by processing 1000 messages.</p> <p>The single processor version:</p> <pre class="brush: c-sharp;"> using (var queue = new MessageQueue(QueuePath)) { queue.Formatter = new BinaryMessageFormatter(); var message = new OrderMessage() { Recipients = "[email protected]", Sender = "[email protected]", Subject = "Hello World", Body = emailBody // loaded from a file }; // Send messages to the queue for (var i = 0; i &lt; 1000; i++) { queue.Send(message); } var fileMailer = new FileSmtpMailer(@"C:\temp"); var command = new MailProcessorCommand(fileMailer); var timerCommand = new TimerCommandDecorator&lt;OrderMessage&gt;(command); var queueMonitor = new QueueMonitor&lt;OrderMessage&gt;(queue, timerCommand); queueMonitor.Start(); } </pre> <pre>Processing 1000 messages took 47.3004132 sec </pre> <p>The competing consumer processor version with 10 processors:</p> <pre class="brush: c-sharp;"> // Create 10 processors var commands = new List&lt;ICommand&lt;OrderMessage&gt;&gt;(); for (var i = 0; i &lt; 10; i++) { commands.Add(new MailProcessorCommand(fileMailer)); } var command = new CompositeCompetingCommandProcessor&lt;OrderMessage&gt;(commands); var timerCommand = new TimerCommandDecorator&lt;OrderMessage&gt;(command); var queueMonitor = new QueueMonitor&lt;OrderMessage&gt;(queue, timerCommand); queueMonitor.Start(); </pre> <pre>Processing 1000 messages took 16.241723 sec </pre> <div class="alert alert-success" role="alert"> <b>Success!</b> The competing consumer pattern processed the mail queue 3 times faster. </div> <p>We could experiment using various numbers of concurrent receivers to determine how performance will be affected.</p> <div class="alert alert-warning" role="alert"> <b>Note:</b> The disk was saturated with request and was running at 100% capacity. </div> <p>The competing consumer pattern is a great option to fully utilize resources but it may have a negative impact on other tenants of the system. For example, if we call an external API with too many requests, it may appear like a denial-of-service attack.</p> <h3>Summary</h3> <p>The advantage of the competing consumers pattern is the flexibility to configure the number of concurrent consumers to produce a balanced outcome. It is however difficult to determine the throughput and performance impact without instrumentation in place to measure resource utilization.</p> <p>An approach was covered to add performance instrumentation. The performance metrics revealed that the queue processing throughput can be improved significantly using the competing consumer queue processor compared to the single queue processor.</p> /post/push-queue-processing-boundaries-with-3x-greater-throughput [email protected] /post/push-queue-processing-boundaries-with-3x-greater-throughput#comment /post.aspx?id=53660465-0890-4eaf-bae1-d3bb61b8a9a6 Sat, 26 Dec 2015 10:54:00 +1300 Decorator Pattern Queues .NET C# Decorator Design Pattern Jay Strydom /pingback.axd /post.aspx?id=53660465-0890-4eaf-bae1-d3bb61b8a9a6 0 /trackback.axd?id=53660465-0890-4eaf-bae1-d3bb61b8a9a6 /post/push-queue-processing-boundaries-with-3x-greater-throughput#comment /syndication.axd?post=53660465-0890-4eaf-bae1-d3bb61b8a9a6 How to make your application 5x faster with background processing <img src="/pics/banners/5XPerformanceGainBlog.jpg" class="img-responsive" alt="5X Performance Gain"> <br> <p> Processing everything in real-time is easy but often makes an application tightly coupled, prone to failure and difficult to scale. </p> <p> Let�s assume a user just clicked on the purchase button to kick off the following workflow: </p> <ol> <li>Save the order</li> <li>Send a confirmation email (mask the credit card number)</li> <li>Update the user�s loyalty points in an external system</li> </ol> <p> <b>The problem</b> is that non-critical workloads (step 2 and 3) can negatively impact an application's performance and recoverability. What happens when the mail server is down and the email confirmation fails? How do we monitor failure? Do we roll the transaction back or replay the workflow by taking a checkpoint after each successful step? </p> <p> <b>The solution</b> is to ensure that application flow isn't impeded by waiting on non-critical workloads to complete. Queue based systems are effective at solving this problem.</p> <p> This post will use a purchase order application that accepts XML requests. The application will sanitise the credit card details by masking most of the digits before sending the request to a mailbox. </p> <a href="/Downloads/SmtpQueuePerformanceExample.zip" role="button" class="btn btn-primary btn-sm">Download Source Code</a> <h3>Setup</h3> <p>The following XML document will be used as the purchase order. It is about 512KB to simulate a decent payload.</p> <pre class="brush: xml;"> <!--?xml version="1.0" encoding="utf-8" ?--> <order> <account> <name>Test User</name> <address>123 Abc Road, Sydney, Australia</address> <payment> <type>Visa</type> <cardnumber>4111111111111111</cardnumber> </payment> </account> <catalog> <book id="bk101"> <author>Gambardella, Matthew</author> <title>XML Developer's Guide</title> </book> ... </catalog></order></pre> The PurchaseOrderProcessor class was intentionally kept small to focus on solving the main problem, which is to minimise the performance impact of the mailing system. <pre class="brush: c-sharp;"> public interface IMailer { void Send(string message); } public class PurchaseOrderProcessor { private readonly IMailer _mailer; public PurchaseOrderProcessor(IMailer mailer) { if (mailer == null) throw new ArgumentNullException("mailer"); _mailer = mailer; } public void Process(string xmlRequest) { var doc = new XmlDocument(); doc.LoadXml(xmlRequest); // Process the order _mailer.Send(xmlRequest); } } </pre> The SMTP mailer will be configured to write the mail to disk to simplify the illustration. <pre class="brush: c-sharp;"> public class FileSmtpMailer : IMailer { private readonly string _path; private readonly string _from; private readonly string _recipients; private readonly string _subject; public FileSmtpMailer(string path, string from, string recipients, string subject) { if (path == null) throw new ArgumentNullException("path"); _path = path; _from = @from; _recipients = recipients; _subject = subject; } public void Send(string message) { using (var client = new SmtpClient()) { // This can be configured in the app.config client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory; client.PickupDirectoryLocation = _path; using (var mailMessage = new MailMessage(_from, _recipients, _subject, message)) { client.IsBodyHtml = true; client.Send(mailMessage); } } } } </pre> The MaskedMailerDecorator will be used for masking the credit card details. <pre class="brush: c-sharp;"> public class MaskedMailerDecorator : IMailer { private readonly Regex _validationRegex; private readonly IMailer _next; private const char MaskCharacter = '*'; private const int MaskDigits = 4; public MaskedMailerDecorator(Regex regex, IMailer next) { if (regex == null) throw new ArgumentNullException("regex"); if (next == null) throw new ArgumentNullException("next"); _validationRegex = regex; _next = next; } public void Send(string message) { if (_validationRegex.IsMatch(message)) { message = _validationRegex.Replace(message, match =&gt; MaskNumber(match.Value)); } _next.Send(message); } private static string MaskNumber(string value) { return value.Length &lt;= MaskDigits ? new string(MaskCharacter, value.Length) : string.Format("{0}{1}", new string(MaskCharacter, value.Length - MaskDigits), value.Substring(value.Length - MaskDigits, MaskDigits)); } } </pre> <h3>Baseline</h3> <p>Let's establish a performance baseline by running the application with the Null Mailer that doesn't do anything. Refer to the <a href="/post/reject-the-null-checked-object">reject the null checked object</a> post if you are new to the null object pattern.</p> <pre class="brush: c-sharp;"> public class NullMailer : IMailer { public void Send(string message) { // intentionally blank } } static void Main(string[] args) { var path = Path.Combine(Directory.GetCurrentDirectory(), "PurchaseOrder.xml"); var request = File.ReadAllText(path); var nullMailer = new NullMailer(); var orderProcessor = new PurchaseOrderProcessor(nullMailer); var stopWatch = Stopwatch.StartNew(); Parallel.For(0, 1000, i =&gt; orderProcessor.Process(request)); stopWatch.Stop(); Console.WriteLine("Seconds: {0}", stopWatch.Elapsed.TotalSeconds); Console.ReadLine(); } </pre> <pre>Seconds: 6.3404086 </pre> <h3>Real-Time Processing</h3> Let�s measure the performance when MaskedMailerDecorator and FileSmtpMailer are used. <pre class="brush: c-sharp;"> Directory.CreateDirectory(@"C:\temp"); var ccRegEx = new Regex(@"(?:\b4[0-9]{12}(?:[0-9]{3})?\b |\b5[1-5][0-9]{14}\b)", RegexOptions.Compiled); var path = Path.Combine(Directory.GetCurrentDirectory(), "PurchaseOrder.xml"); var request = File.ReadAllText(path); // Use Unity for doing the wiring var fileMailer = new FileSmtpMailer(@"C:\temp", "[email protected]", "[email protected]", "Order"); var maskedMailer = new MaskedMailerDecorator(ccRegEx, fileMailer); var orderProcessor = new PurchaseOrderProcessor(maskedMailer); var stopWatch = Stopwatch.StartNew(); Parallel.For(0, 1000, i =&gt; orderProcessor.Process(request)); stopWatch.Stop(); Console.WriteLine("Seconds: {0}", stopWatch.Elapsed.TotalSeconds); Console.ReadLine(); </pre> <pre>Seconds: 32.0430142 </pre> <div class="alert alert-danger" role="alert"> <b>Outch!</b> The application took 5x longer to process the same number of requests. </div> <h3>Background Processing</h3> <p>Let's extend the solution by adding a memory queue to buffer the results. The queue effectively acts as an outbox for sending mail without overwhelming the mail server with parallel requests.</p> <pre class="brush: c-sharp;"> public class QueuedMailerDecorator : IMailer { private readonly IMailer _next; private BlockingCollection&lt;string&gt; _messages; public QueuedMailerDecorator(IMailer next) { if (next == null) throw new ArgumentNullException("next"); _next = next; _messages = new BlockingCollection&lt;string&gt;(); Task.Factory.StartNew(() =&gt; { try { // Block the thread until a message becomes available foreach (var message in _messages.GetConsumingEnumerable()) { _next.Send(message); } } finally { _messages.Dispose(); } }, TaskCreationOptions.LongRunning); } public void Send(string message) { if (_messages == null || _messages.IsAddingCompleted) { return; } try { _messages.TryAdd(message); } catch (ObjectDisposedException) { Trace.WriteLine("Add failed since the queue was disposed."); } } public void Dispose() { if (_messages != null &amp;&amp; !_messages.IsAddingCompleted) { _messages.CompleteAdding(); } GC.SuppressFinalize(this); } } </pre> <p>Here is a diagram that depicts the collection of decorated mailers to intercept the communication between the PurchaseOrderProcessor and the FileSmtpMailer.</p> <p> <img src="/pics/blogs/SmtpMailerDecorator.png" class="img-responsive" alt="SMTP Mailer Decorators"> </p> Let's run the code below to evaluate if the queue made a performance difference. <pre class="brush: c-sharp;"> // Use Unity for doing the wiring var fileMailer = new FileSmtpMailer(@"C:\temp", "[email protected]", "[email protected]", "Order"); var maskedMailer = new MaskedMailerDecorator(creditCardRegEx, fileMailer); var queuedMailer = new QueuedMailerDecorator(maskedMailer); var orderProcessor = new PurchaseOrderProcessor(queuedMailer); var stopWatch = Stopwatch.StartNew(); Parallel.For(0, 1000, i =&gt; orderProcessor.Process(request)); stopWatch.Stop(); Console.WriteLine("Seconds: {0}", stopWatch.Elapsed.TotalSeconds); Console.ReadLine(); </pre> <pre>Seconds: 6.3908034 </pre> <div class="alert alert-success" role="alert"> <b>Success!</b> The performance of the file mailer was nearly identical to the results without a mailer. </div> <p><b>The drawback</b> of the in-memory queue used in this post is that it requires memory to store messages temporarily before it is processed. It is possible to lose messages if the application crashes or stops unexpectedly before all of the requests have been processed.</p> <p>These issues can be addressed with a locally persisted queue such as MSMQ or a cloud based queue such as Azure Service Bus. Queues provide many benefits that will be covered in the next post.</p> <h3>Summary</h3> This post provided evidence to the performance degradation caused by processing non-critical workloads in real-time. Using queues can be an effective technique to keep an application responsive by buffering and processing tasks in the background. /post/how-to-make-your-application-5x-faster-with-background-processing [email protected] /post/how-to-make-your-application-5x-faster-with-background-processing#comment /post.aspx?id=3232dd7f-e387-4eb3-b989-9b96d75a4419 Tue, 15 Dec 2015 07:41:00 +1300 Design Patterns Decorator Pattern Null Object Pattern Software Design Queues Decorator Design Pattern Design Patterns C# .NET Jay Strydom /pingback.axd /post.aspx?id=3232dd7f-e387-4eb3-b989-9b96d75a4419 0 /trackback.axd?id=3232dd7f-e387-4eb3-b989-9b96d75a4419 /post/how-to-make-your-application-5x-faster-with-background-processing#comment /syndication.axd?post=3232dd7f-e387-4eb3-b989-9b96d75a4419