KnowDotNet NetRefactor

Data Access Patterns [Retryer]

by William Ryan
Print this Article Discuss in Forums

There are many books dedicated to the subject of Software Design Patterns and the subject is becoming increasingly hard to ignore.  Microsoft for instance has dedicated an entire Community dedicated to the subject of patterns and practices.  I'm not going to try to hard sell the concept of Pattern based design on you.  All I will say is that for a while, I had a somewhat difficult time understanding the real world applicability of using patterns but as I became more and more familiar with them - it's hard to imagine life without them.

There are many different types of Patterns like Data Access, Integration   and Testing Software , but this just scarcely scratches the surface.  And to be perfectly honest, in the last two jobs I interviewed for, I qot a pretty good amount of questions on patterns, which ones I've used and why I chose them.  I'm hearing this more and more.

Anyway, I'm going to focus on Data Access patterns, one in particular named the Retryer. Before I start - I want to point out that I did not write this pattern and in no way claim I did it.  Actually, I got it out of Clifton Nock's Data Access Patterns Database Interactions in Object Oriented Applications.  The code used in there was done in Java and JDBC - but patterns are ways to solve problems - the implementation will vary from language to language or framework to framework.  I've  ported it over to C# and did a small integration with Microsoft's Data Access Application Block.

According to the description on page 171 - Retryer should "Automatically retries operations whose failure is expected under certain defined conditions.  This pattern enables fault-tolerance for data access operations"

First off - Data Access operations are notably different from many other types of functions in that there is a lot of interdependency among different components and failure of any one piece will cause the system to fail. This is particularly true in Client/Server or N-Tier scenarioes.

For instance, if I have a traditional Client/Server application that queries a database - my code can fail because the database goes down.  My code should bow out gracefully - but the show can't go on until we get another connection to the db.  This can be mitigated somewhat in more disconnected scenarios - but at some point that data needs to get back into the database or my app won't be worth anything to the users.  But let's say the Network goes down.  All of a sudden, I can't continue.  What if my Database goes down, same thing?  Network card?  Same.  You get the idea.  None of this would be considered a bug on my part - but it's still a problem (unless I somehow coded it in a way that caused the problem directly but I think you get the idea).

Now, let's look at a "bad" way of dealing with this.  You can a method that calls the .Open method on the dbConnection and if it doens't immediately open, a new connection is created inside a loop until we get a clean open or some interval passes, which happens first.  This is probably the worst possible way to handle this situation but one that's very common in practice.  Why is it so bad?

You have a limited number of connections out there.  So something could be causing the first one to open slowly - maybe it's waiting for an available connection, but since it doesn't respond fast enough - you start piling more stress on it.  So does every user out there.  Each one of those Connection.Open()'s isn't probably getting a Connection.Close() - that would be an ugly thing to implement considering how they were opened, so in a nutshell, your 'solution' to  a timeout is precisely something that WILL in all likelihood cause a whole bunch of other timeouts and exceptions.  Hardly a solution right?

In comes patterns to the rescue.

First a refresher course on Interfaces and Inheritance.

Let's say that I have the following Interface:

using System;
using System.Data;

namespace InterfacesSample
{
  
/// <summary>
  /// Summary description for IGenericInterface.
  ///
  public interface IGenericInterface
   {
       System.String ClassName();
       System.DateTime AccessTime();
   }
}

---------------
Next, I decide to create three separate classes that are totally different, but all implement this interface:

using System;
using System.Data;

namespace InterfacesSample
{

public class FirstIGenericClass : IGenericInterface
{
  
public FirstIGenericClass(){}
   #region IGenericInterface Members
  
public String ClassName()
   {
      
return "FirstIGenericClass";
   }
  
public DateTime AccessTime()
   {        
      
return DateTime.Now;
   }
   #endregion
}
}

using System;
using System.Data;

namespace InterfacesSample
{

public class SecondIGenericClass : IGenericInterface
{
  
public SecondIGenericClass(){}
   #region IGenericInterface Members
  
public String ClassName()
   {
      
return "SecondIGenericClass";
   }
  
public DateTime AccessTime()
   {        
      
return DateTime.Now;
   }
   #endregion
}
}
using System;
using System.Data;

namespace InterfacesSample
{
public class ThirdIGenericClass : IGenericInterface
{
  
public ThirdIGenericClass(){}
   #region IGenericInterface Members
  
public String ClassName()
   {
      
return "ThirdIGenericClass";
   }
  
public DateTime AccessTime()
   {        
      
return DateTime.Now;
   }
   #endregion
}
}
--------------
Now assume that I have the following function:

private void DemoInterfaceBehavior(IGenericInterface obj)
{        
    rtb.Text += obj.ClassName() + " " +
           obj.AccessTime().ToString() + "\r\n";
}

Would you expect that the following code will work, successfully passing in each of the objects and then outputting the respective information?

private void button1_Click(object sender, System.EventArgs e)
{
    FirstIGenericClass cs =
new FirstIGenericClass();
    SecondIGenericClass cs2 =
new SecondIGenericClass();
    ThirdIGenericClass cs3 =
new ThirdIGenericClass();
  
this.DemoInterfaceBehavior(cs);
  
this.DemoInterfaceBehavior(cs2);
  
this.DemoInterfaceBehavior(cs3);
}

Well, the first inclination might be to say "NO" but you'd be wrong.  You see, obj is of type IGenericInterface which has two methods ClassName and AccessTime.  As such, any object that implements this interface will have at least those two methods as well.  Since all three classes (FirstIGenericClass, SecondIGenericClass and ThirdIGenericClass) all implement the IGenericInterface Interface - all is good.

Back to the retryer pattern:

The key to this whole thing working is the IRetryable Interface shown below:

using System;
using System.Data;

namespace Ryan.Patterns.Data.Retryer.Core
{
/// <summary>
///
Summary description for IRetryable.
///
public interface IRetryable
{  
#region Public Methods
  
/// <summary>
  /// Attemps to retry something - once.
  ///
  /// <returns>
   System.Boolean Attempt();
  
/// <summary>
  /// Recovers from an operation failure
  ///
  void Recover();
#endregion
}
}

Pretty simple - actually, it couldn't be much easier to create.  Now for the Retryer class:

using System;
using System.Data;
using System.Threading;
using Ryan.Patterns.Data.Retryer.Exceptions;
namespace Ryan.Patterns.Data.Retryer.Core
{
/// <summary>
///
Summary description for Retryer.
///
public class Retryer
{
  
private IRetryable operation;
  
private System.Int32 maxAttempts;
  
private System.Int32 retryInterval;

public System.Int32 MaximumAttempts
{
  
get {
        
return this.maxAttempts;
   }
  
set {
      
this.maxAttempts = value;
   }
}

public System.Int32 RetryInterval
{
  
get {
        
return this.retryInterval;
   }
  
set {
        
this.retryInterval = value;
   }
}
public Retryer(IRetryable operation)
{
  
this.operation =  operation;
}

public void Perform(System.Int32 maximumAttempts,
    System.Int32 attemptInterval){
  
this.MaximumAttempts = maximumAttempts;
  
this.RetryInterval = attemptInterval;
    System.Boolean succeeded =
false;

  
for(System.Int32 x = 1; (x <= thisMaximumAttempts
       ||
this.MaximumAttempts < 0) && !succeeded; x++){<BR>             
       succeeded =
this.operation.Attempt();
      
if(!succeeded){
        
this.operation.Recover();
          Thread.Sleep(
this.RetryInterval);
      }
   }

  
if(!succeeded){
       System.String Message =
       String.Format("After {0} tries, this operation could " +
              " not be completed.  {1}"
             ,
this.MaximumAttempts
             , DateTime.Now.ToString());

        
throw new RetryFailedException(Message);
      }
   }
   }

}

The piece to look at here is the Constructor that takes a IRetryable as a Parameter.  This means that you can pass in ANY IRetryable object and this implementation will try it according to the number of intervals specified and the lenght of interval specified.  I actually stored this in various .config files but you can pass them in if you like.  Now, I'm just raising an exception if I get a failure here but in a more Enterprise scenario - one I'm working on at work right now - you could switch modes if the Database is down and start writing to a MessageQueue - which is very powerful, has transactional support, fully supported via distributed transactions and is easy to use.  But MessageQueueing is an area unto itself.  Ok, now for a simple implementation (indicidentally, I am using the Data Access Application Block - and actually this article is based on a bigger one I'm trying to finish on extending the DAAB):


using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using Microsoft.ApplicationBlocks.Data;
using System.Configuration;
namespace Ryan.Patterns.Data.Retryer.Core
{
/// <summary>
///
Summary description for Class1.
///
public class UpdateHanlder : IRetryable
{
public UpdateHanlder(){}
#region IRetryable Members
public void Recover() {
  
// ADD Logging code or send the stuff to another db - whatever you want
}

public bool Attempt() {
// TODO:  Add UpdateHanlder.Attempt implementation
SqlConnection cn =
        
new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings ["ConnectionString"]);
    System.String sql = "INSERT INTO TESTTABLE (VEHICLEYEAR) VALUES (@VehicleYear)";
    SqlParameter prm =
new SqlParameter("@VehicleYear", SqlDbType.Int);
    prm.Value = 2010;
    SqlParameter[] Params = {prm};
    System.Int32 RecsAffected = SqlHelper.ExecuteNonQuery(cn, CommandType.Text, sql, Params);
  
return (RecsAffected > 0) ? true : false;
}
#endregion
  }
}

Now, the way exceptions behave in .NET needs to be accounted for in the NET IMplementation of this pattern.  The behavior is different in different environments so there is some tailoring that needs done.  In this case - simply trapping an ApplicationException in the Attempt() method should do it - and if the exception is caught - return false.  There are so  many different approaches you  could take, from using the Exception Management block or Log4Net to whatever else  - but it really doesn't matter - what does is that you address it by returning false.

In just one book there are probably about 70-100 Patterns dealing exclusively with Data Access - telling you that it's not exactly a trivial area.  Plus, there will no doubt be new ones that emerge or are refined.  But hopefully you have a taste for how such a pattern might work and be implemented.  More to come...

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing