Geeks With Blogs
On the Ledge The general evolution (and occasional regression) of a .NET developer

We get Flumphs from several, different providers.  Each provider has various settings that the system uses for them - particular URL routes, specific timeouts, etc.  In the old Proxy, anything that absolutely had to be client-specific was stored in a configuration file.  The timeout limit was universal.  Here's the kicker - the only thing in the Flumph that gets sent to us that clues us into the provider is the structure of the XML.  Since our Flumph providers delight in sending their own formats, we can't count on a specific identifier for the provider being in the XML - or any identifier at all, in some cases.

So, we need a way that can identify the provider and retrieve their specific, custom settings without hitting the database several times a second to pull information that rarely changes.  Here's what I did:

First, I made a class called ConfigurationSettings which has the following kinds of fields: constants that define the keys we'll use for the database lookup and the cache, constants that represent defaults in case the values can't be found, and collections (mostly string, string Dictionaries) to hold the settings in different groups.  This class will hold all our settings for all our providers.

Some examples:

public const string TimeOutsKey = "TimeOuts";
public const int DefaultTimeOut = 18;
public IDictionary<string, string> TimeOuts;

 

In those examples, you see how we specified the key for looking up TimeOut settings, a default timeout for universal use (in other words, we can't find this provider's timeout in our TimeOuts collection, so we'll use this one), and a collection of all our providers' timeouts.  I used timeouts for the examples because that's what precipitated this need, but we do the same thing to store a provider's domains, restrictions, XML format info, and application settings in general.

The XML format info is done a bit differently - it's a collection of SourceXmlSetting objects - a class I wrote that stores things like RootNodeName, SourceNodeName, and some other stuff.  But aside from that twist, it works pretty much the same way.

We then have a number of static methods.

GetConfigurationSettings() is a private static method that hits the database and populates our collections.  This is very straightforward.  The configuration settings are in one table, the XML format info is in another table.  This method just hits both tables, iterates through them, and adds an item to the appropriate collection.

For example, the ConfigurationSettings table has three fields: Type, Key, and Value.  "Type" refers to our categories of information, like "TimeOuts."  This is where the constant fields are helpful in making sure we use the same types in both the database and cache retrieval.  "Key" and "Value" are pretty straightforward.  So, you might have a record in this table that looks like: "TimeOuts", "LS15U", 30.  The first is the type, the second is the key (which is the provider name/code), and the third is the value, which is 30 seconds in this case.

As our code iterates through this table with a datareader, a switch/case statement on the "Type" field tells us which dictionary to put the key-value pair into.  Once this is done, a very similar thing happens with the XmlRequests table, except, once again, several fields of information are involved, so this is stored in a custom collection of a custom class to hold the data.

Note that this method is private.  Calling code cannot directly cause ConfigurationSettings to populate.  We do, however, have a public static method called LoadConfigurationSettingsIntoCache which our calling code does use when our populated ConfigurationSettings are no longer found in the cache.

public static void LoadConfigurationSettingsIntoCache() 
{
  ConfigurationSettings configurationSettings = GetConfigurationSettings();
  HttpRuntime.Cache.Insert(CacheKey, configurationSettings, null, DateTime.Now.AddHours(1), TimeSpan.Zero);
}

 

As you can see, we cache this data for an hour.  The data doesn't change nearly that frequently, but when you plan caching, you also have to plan how long you want changes to take.  This way, if we have to change someone's timeout, the longest we wait is an hour.  Ideally, we would probably cache these settings longer and provide some other mechanism to flush the cache if we change the info in the database.  We have not done that, yet.

We also have a handful of static methods used to get commonly accessed settings, like GetTimeOut, GetRequestRoot, and so on.

When our proxy receives a request, the first thing it does is look for the ConfigurationSettings in the cache.  If it's there, great.  If not, it calls the LoadConfigurationSettingsIntoCache() method, which puts it there.  Any exception causes an XML response to be sent back to the provider that the system is currently offline for maintenance.

With that collection of settings in the Cache, retrieval of client-specific settings is a breeze.  We can either use one of our little helper static methods to quickly pull out commonly-used data, and we can just access the ConfigurationSettings' collections directly for all other operations:

_timeOut = ConfigurationSettings.GetTimeOut(_source, _configurationSettings.TimeOuts);

 

or

foreach (SourceXmlSetting setting in _configurationSettings.XmlSettings)

 

for example.

Once again, it all comes down to what kind of data you've got, how regularly it changes, and the costs and benefits of how you handle persisting and retrieving that data.  For us, this data rarely changes, and our high volume of requests is just begging to make this information available without a database hit.  Also, this particular solution means we can add more settings or change them without recompiling or redeploying anything - not even a config file.

There are two, main improvements I would like to make:

  • Reloading into the cache every hour is still too often, I feel.  These settings change once in a blue moon except for the flag that marks our system down for maintenance, which still only changes once or twice a month.  I'd like to have the data cached longer and code a specific XML request we could send to the Proxy that would cause it to flush and reload the cache.
  • We can add new settings without changing code.  We can't add new types of settings.  If we wanted to store, say, a provider's maximum allowable volume, we'd have to make a few alterations to the ConfigurationSettings class.  I'd like to abstract those collections further - maybe implementing a common base class - so that ConfigurationSettings could just deal intelligently with a generic "collection of collections."  Then, if we wanted to add new kinds of configuration settings, we could just create a new collection that inherited from that base class, load it up, and add it to ConfigurationSettings without actually changing the ConfigurationSettings class.

But, if wishes were horses, you could make baseballs for the rest of your life.  Our current setup works great for our current needs, and one of the cool things about where I work is that we set time specifically for refactoring old code, so I might get my wish at some point.

Posted on Friday, September 25, 2009 10:51 AM How-To , Proxy | Back to top


Comments on this post: Custom User Settings and the Cache

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © ledge | Powered by: GeeksWithBlogs.net